diff --git a/docs/apm/troubleshooting.asciidoc b/docs/apm/troubleshooting.asciidoc index 65f7a378ec24..e00a67f6c78a 100644 --- a/docs/apm/troubleshooting.asciidoc +++ b/docs/apm/troubleshooting.asciidoc @@ -49,7 +49,7 @@ GET /_template/apm-{version} *Using Logstash, Kafka, etc.* If you're not outputting data directly from APM Server to Elasticsearch (perhaps you're using Logstash or Kafka), then the index template will not be set up automatically. Instead, you'll need to -{apm-server-ref}/_manually_loading_template_configuration.html[load the template manually]. +{apm-server-ref}/configuration-template.html[load the template manually]. *Using a custom index names* This problem can also occur if you've customized the index name that you write APM data to. diff --git a/docs/development/core/server/kibana-plugin-core-server.md b/docs/development/core/server/kibana-plugin-core-server.md index 89330d2a86f7..dfffdffb08a0 100644 --- a/docs/development/core/server/kibana-plugin-core-server.md +++ b/docs/development/core/server/kibana-plugin-core-server.md @@ -123,7 +123,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [LoggerFactory](./kibana-plugin-core-server.loggerfactory.md) | The single purpose of LoggerFactory interface is to define a way to retrieve a context-based logger instance. | | [LoggingServiceSetup](./kibana-plugin-core-server.loggingservicesetup.md) | Provides APIs to plugins for customizing the plugin's logger. | | [LogMeta](./kibana-plugin-core-server.logmeta.md) | Contextual metadata | -| [MetricsServiceSetup](./kibana-plugin-core-server.metricsservicesetup.md) | | +| [MetricsServiceSetup](./kibana-plugin-core-server.metricsservicesetup.md) | APIs to retrieves metrics gathered and exposed by the core platform. | | [NodesVersionCompatibility](./kibana-plugin-core-server.nodesversioncompatibility.md) | | | [OnPostAuthToolkit](./kibana-plugin-core-server.onpostauthtoolkit.md) | A tool set defining an outcome of OnPostAuth interceptor for incoming request. | | [OnPreAuthToolkit](./kibana-plugin-core-server.onpreauthtoolkit.md) | A tool set defining an outcome of OnPreAuth interceptor for incoming request. | diff --git a/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.collectioninterval.md b/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.collectioninterval.md new file mode 100644 index 000000000000..6f05526b66c8 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.collectioninterval.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [MetricsServiceSetup](./kibana-plugin-core-server.metricsservicesetup.md) > [collectionInterval](./kibana-plugin-core-server.metricsservicesetup.collectioninterval.md) + +## MetricsServiceSetup.collectionInterval property + +Interval metrics are collected in milliseconds + +Signature: + +```typescript +readonly collectionInterval: number; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.getopsmetrics_.md b/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.getopsmetrics_.md new file mode 100644 index 000000000000..61107fbf20ad --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.getopsmetrics_.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [MetricsServiceSetup](./kibana-plugin-core-server.metricsservicesetup.md) > [getOpsMetrics$](./kibana-plugin-core-server.metricsservicesetup.getopsmetrics_.md) + +## MetricsServiceSetup.getOpsMetrics$ property + +Retrieve an observable emitting the [OpsMetrics](./kibana-plugin-core-server.opsmetrics.md) gathered. The observable will emit an initial value during core's `start` phase, and a new value every fixed interval of time, based on the `opts.interval` configuration property. + +Signature: + +```typescript +getOpsMetrics$: () => Observable; +``` + +## Example + + +```ts +core.metrics.getOpsMetrics$().subscribe(metrics => { + // do something with the metrics +}) + +``` + diff --git a/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.md b/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.md index 0bec919797b6..5fcb1417dea0 100644 --- a/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.md +++ b/docs/development/core/server/kibana-plugin-core-server.metricsservicesetup.md @@ -4,8 +4,18 @@ ## MetricsServiceSetup interface +APIs to retrieves metrics gathered and exposed by the core platform. + Signature: ```typescript export interface MetricsServiceSetup ``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [collectionInterval](./kibana-plugin-core-server.metricsservicesetup.collectioninterval.md) | number | Interval metrics are collected in milliseconds | +| [getOpsMetrics$](./kibana-plugin-core-server.metricsservicesetup.getopsmetrics_.md) | () => Observable<OpsMetrics> | Retrieve an observable emitting the [OpsMetrics](./kibana-plugin-core-server.opsmetrics.md) gathered. The observable will emit an initial value during core's start phase, and a new value every fixed interval of time, based on the opts.interval configuration property. | + diff --git a/docs/development/core/server/kibana-plugin-core-server.opsmetrics.collected_at.md b/docs/development/core/server/kibana-plugin-core-server.opsmetrics.collected_at.md new file mode 100644 index 000000000000..25125569b7b3 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.opsmetrics.collected_at.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [OpsMetrics](./kibana-plugin-core-server.opsmetrics.md) > [collected\_at](./kibana-plugin-core-server.opsmetrics.collected_at.md) + +## OpsMetrics.collected\_at property + +Time metrics were recorded at. + +Signature: + +```typescript +collected_at: Date; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.opsmetrics.md b/docs/development/core/server/kibana-plugin-core-server.opsmetrics.md index d2d4782385c0..9803c0fbd53c 100644 --- a/docs/development/core/server/kibana-plugin-core-server.opsmetrics.md +++ b/docs/development/core/server/kibana-plugin-core-server.opsmetrics.md @@ -16,6 +16,7 @@ export interface OpsMetrics | Property | Type | Description | | --- | --- | --- | +| [collected\_at](./kibana-plugin-core-server.opsmetrics.collected_at.md) | Date | Time metrics were recorded at. | | [concurrent\_connections](./kibana-plugin-core-server.opsmetrics.concurrent_connections.md) | OpsServerMetrics['concurrent_connections'] | number of current concurrent connections to the server | | [os](./kibana-plugin-core-server.opsmetrics.os.md) | OpsOsMetrics | OS related metrics | | [process](./kibana-plugin-core-server.opsmetrics.process.md) | OpsProcessMetrics | Process related metrics | diff --git a/docs/development/core/server/kibana-plugin-core-server.opsosmetrics.cpu.md b/docs/development/core/server/kibana-plugin-core-server.opsosmetrics.cpu.md new file mode 100644 index 000000000000..095c45266a25 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.opsosmetrics.cpu.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [OpsOsMetrics](./kibana-plugin-core-server.opsosmetrics.md) > [cpu](./kibana-plugin-core-server.opsosmetrics.cpu.md) + +## OpsOsMetrics.cpu property + +cpu cgroup metrics, undefined when not running in a cgroup + +Signature: + +```typescript +cpu?: { + control_group: string; + cfs_period_micros: number; + cfs_quota_micros: number; + stat: { + number_of_elapsed_periods: number; + number_of_times_throttled: number; + time_throttled_nanos: number; + }; + }; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.opsosmetrics.cpuacct.md b/docs/development/core/server/kibana-plugin-core-server.opsosmetrics.cpuacct.md new file mode 100644 index 000000000000..140646a0d1a3 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.opsosmetrics.cpuacct.md @@ -0,0 +1,16 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [OpsOsMetrics](./kibana-plugin-core-server.opsosmetrics.md) > [cpuacct](./kibana-plugin-core-server.opsosmetrics.cpuacct.md) + +## OpsOsMetrics.cpuacct property + +cpu accounting metrics, undefined when not running in a cgroup + +Signature: + +```typescript +cpuacct?: { + control_group: string; + usage_nanos: number; + }; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.opsosmetrics.md b/docs/development/core/server/kibana-plugin-core-server.opsosmetrics.md index 5fedb76a9c8d..893860853113 100644 --- a/docs/development/core/server/kibana-plugin-core-server.opsosmetrics.md +++ b/docs/development/core/server/kibana-plugin-core-server.opsosmetrics.md @@ -16,6 +16,8 @@ export interface OpsOsMetrics | Property | Type | Description | | --- | --- | --- | +| [cpu](./kibana-plugin-core-server.opsosmetrics.cpu.md) | {
control_group: string;
cfs_period_micros: number;
cfs_quota_micros: number;
stat: {
number_of_elapsed_periods: number;
number_of_times_throttled: number;
time_throttled_nanos: number;
};
} | cpu cgroup metrics, undefined when not running in a cgroup | +| [cpuacct](./kibana-plugin-core-server.opsosmetrics.cpuacct.md) | {
control_group: string;
usage_nanos: number;
} | cpu accounting metrics, undefined when not running in a cgroup | | [distro](./kibana-plugin-core-server.opsosmetrics.distro.md) | string | The os distrib. Only present for linux platforms | | [distroRelease](./kibana-plugin-core-server.opsosmetrics.distrorelease.md) | string | The os distrib release, prefixed by the os distrib. Only present for linux platforms | | [load](./kibana-plugin-core-server.opsosmetrics.load.md) | {
'1m': number;
'5m': number;
'15m': number;
} | cpu load metrics | diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.md index 6ef7b991bb15..650459bfdb43 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.md @@ -16,8 +16,6 @@ export interface SavedObjectsServiceSetup When plugins access the Saved Objects client, a new client is created using the factory provided to `setClientFactory` and wrapped by all wrappers registered through `addClientWrapper`. -All the setup APIs will throw if called after the service has started, and therefor cannot be used from legacy plugin code. Legacy plugins should use the legacy savedObject service until migrated. - ## Example 1 diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.registertype.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.registertype.md index 57c9e04966c1..54e01d3110a2 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.registertype.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsservicesetup.registertype.md @@ -14,10 +14,6 @@ See the [mappings format](./kibana-plugin-core-server.savedobjectstypemappingdef registerType: (type: SavedObjectsType) => void; ``` -## Remarks - -The type definition is an aggregation of the legacy savedObjects `schema`, `mappings` and `migration` concepts. This API is the single entry point to register saved object types in the new platform. - ## Example diff --git a/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.dependencies_.md b/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.dependencies_.md new file mode 100644 index 000000000000..7475f0e3a4c1 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.dependencies_.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [StatusServiceSetup](./kibana-plugin-core-server.statusservicesetup.md) > [dependencies$](./kibana-plugin-core-server.statusservicesetup.dependencies_.md) + +## StatusServiceSetup.dependencies$ property + +Current status for all plugins this plugin depends on. Each key of the `Record` is a plugin id. + +Signature: + +```typescript +dependencies$: Observable>; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.derivedstatus_.md b/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.derivedstatus_.md new file mode 100644 index 000000000000..6c65e44270a0 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.derivedstatus_.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [StatusServiceSetup](./kibana-plugin-core-server.statusservicesetup.md) > [derivedStatus$](./kibana-plugin-core-server.statusservicesetup.derivedstatus_.md) + +## StatusServiceSetup.derivedStatus$ property + +The status of this plugin as derived from its dependencies. + +Signature: + +```typescript +derivedStatus$: Observable; +``` + +## Remarks + +By default, plugins inherit this derived status from their dependencies. Calling overrides this default status. + +This may emit multliple times for a single status change event as propagates through the dependency tree + diff --git a/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.md b/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.md index 3d3b73ccda25..ba0645be4d26 100644 --- a/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.md +++ b/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.md @@ -12,10 +12,73 @@ API for accessing status of Core and this plugin's dependencies as well as for c export interface StatusServiceSetup ``` +## Remarks + +By default, a plugin inherits it's current status from the most severe status level of any Core services and any plugins that it depends on. This default status is available on the API. + +Plugins may customize their status calculation by calling the API with an Observable. Within this Observable, a plugin may choose to only depend on the status of some of its dependencies, to ignore severe status levels of particular Core services they are not concerned with, or to make its status dependent on other external services. + +## Example 1 + +Customize a plugin's status to only depend on the status of SavedObjects: + +```ts +core.status.set( + core.status.core$.pipe( +. map((coreStatus) => { + return coreStatus.savedObjects; + }) ; + ); +); + +``` + +## Example 2 + +Customize a plugin's status to include an external service: + +```ts +const externalStatus$ = interval(1000).pipe( + switchMap(async () => { + const resp = await fetch(`https://myexternaldep.com/_healthz`); + const body = await resp.json(); + if (body.ok) { + return of({ level: ServiceStatusLevels.available, summary: 'External Service is up'}); + } else { + return of({ level: ServiceStatusLevels.available, summary: 'External Service is unavailable'}); + } + }), + catchError((error) => { + of({ level: ServiceStatusLevels.unavailable, summary: `External Service is down`, meta: { error }}) + }) +); + +core.status.set( + combineLatest([core.status.derivedStatus$, externalStatus$]).pipe( + map(([derivedStatus, externalStatus]) => { + if (externalStatus.level > derivedStatus) { + return externalStatus; + } else { + return derivedStatus; + } + }) + ) +); + +``` + ## Properties | Property | Type | Description | | --- | --- | --- | | [core$](./kibana-plugin-core-server.statusservicesetup.core_.md) | Observable<CoreStatus> | Current status for all Core services. | +| [dependencies$](./kibana-plugin-core-server.statusservicesetup.dependencies_.md) | Observable<Record<string, ServiceStatus>> | Current status for all plugins this plugin depends on. Each key of the Record is a plugin id. | +| [derivedStatus$](./kibana-plugin-core-server.statusservicesetup.derivedstatus_.md) | Observable<ServiceStatus> | The status of this plugin as derived from its dependencies. | | [overall$](./kibana-plugin-core-server.statusservicesetup.overall_.md) | Observable<ServiceStatus> | Overall system status for all of Kibana. | +## Methods + +| Method | Description | +| --- | --- | +| [set(status$)](./kibana-plugin-core-server.statusservicesetup.set.md) | Allows a plugin to specify a custom status dependent on its own criteria. Completely overrides the default inherited status. | + diff --git a/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.set.md b/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.set.md new file mode 100644 index 000000000000..143cd397c40a --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.statusservicesetup.set.md @@ -0,0 +1,28 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [StatusServiceSetup](./kibana-plugin-core-server.statusservicesetup.md) > [set](./kibana-plugin-core-server.statusservicesetup.set.md) + +## StatusServiceSetup.set() method + +Allows a plugin to specify a custom status dependent on its own criteria. Completely overrides the default inherited status. + +Signature: + +```typescript +set(status$: Observable): void; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| status$ | Observable<ServiceStatus> | | + +Returns: + +`void` + +## Remarks + +See the [StatusServiceSetup.derivedStatus$](./kibana-plugin-core-server.statusservicesetup.derivedstatus_.md) API for leveraging the default status calculation that is provided by Core. + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.getsearchparamsfromrequest.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.getsearchparamsfromrequest.md index 337b4b3302cc..d32e9a955f89 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.getsearchparamsfromrequest.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.getsearchparamsfromrequest.md @@ -9,7 +9,6 @@ ```typescript export declare function getSearchParamsFromRequest(searchRequest: SearchRequest, dependencies: { - esShardTimeout: number; getConfig: GetConfigFn; }): ISearchRequestParams; ``` @@ -19,7 +18,7 @@ export declare function getSearchParamsFromRequest(searchRequest: SearchRequest, | Parameter | Type | Description | | --- | --- | --- | | searchRequest | SearchRequest | | -| dependencies | {
esShardTimeout: number;
getConfig: GetConfigFn;
} | | +| dependencies | {
getConfig: GetConfigFn;
} | | Returns: diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern._constructor_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern._constructor_.md index 2e078e3404fe..a5bb15c96397 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern._constructor_.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern._constructor_.md @@ -9,7 +9,7 @@ Constructs a new instance of the `IndexPattern` class Signature: ```typescript -constructor(id: string | undefined, { savedObjectsClient, apiClient, patternCache, fieldFormats, onNotification, onError, shortDotsEnable, metaFields, }: IndexPatternDeps); +constructor(id: string | undefined, { savedObjectsClient, apiClient, patternCache, fieldFormats, indexPatternsService, onNotification, onError, shortDotsEnable, metaFields, }: IndexPatternDeps); ``` ## Parameters @@ -17,5 +17,5 @@ constructor(id: string | undefined, { savedObjectsClient, apiClient, patternCach | Parameter | Type | Description | | --- | --- | --- | | id | string | undefined | | -| { savedObjectsClient, apiClient, patternCache, fieldFormats, onNotification, onError, shortDotsEnable, metaFields, } | IndexPatternDeps | | +| { savedObjectsClient, apiClient, patternCache, fieldFormats, indexPatternsService, onNotification, onError, shortDotsEnable, metaFields, } | IndexPatternDeps | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md index 4c53af3f8970..87ce1e258712 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.md @@ -14,7 +14,7 @@ export declare class IndexPattern implements IIndexPattern | Constructor | Modifiers | Description | | --- | --- | --- | -| [(constructor)(id, { savedObjectsClient, apiClient, patternCache, fieldFormats, onNotification, onError, shortDotsEnable, metaFields, })](./kibana-plugin-plugins-data-public.indexpattern._constructor_.md) | | Constructs a new instance of the IndexPattern class | +| [(constructor)(id, { savedObjectsClient, apiClient, patternCache, fieldFormats, indexPatternsService, onNotification, onError, shortDotsEnable, metaFields, })](./kibana-plugin-plugins-data-public.indexpattern._constructor_.md) | | Constructs a new instance of the IndexPattern class | ## Properties @@ -29,11 +29,13 @@ export declare class IndexPattern implements IIndexPattern | [id](./kibana-plugin-plugins-data-public.indexpattern.id.md) | | string | | | [intervalName](./kibana-plugin-plugins-data-public.indexpattern.intervalname.md) | | string | undefined | | | [metaFields](./kibana-plugin-plugins-data-public.indexpattern.metafields.md) | | string[] | | +| [originalBody](./kibana-plugin-plugins-data-public.indexpattern.originalbody.md) | | {
[key: string]: any;
} | | | [sourceFilters](./kibana-plugin-plugins-data-public.indexpattern.sourcefilters.md) | | SourceFilter[] | | | [timeFieldName](./kibana-plugin-plugins-data-public.indexpattern.timefieldname.md) | | string | undefined | | | [title](./kibana-plugin-plugins-data-public.indexpattern.title.md) | | string | | | [type](./kibana-plugin-plugins-data-public.indexpattern.type.md) | | string | undefined | | | [typeMeta](./kibana-plugin-plugins-data-public.indexpattern.typemeta.md) | | TypeMeta | | +| [version](./kibana-plugin-plugins-data-public.indexpattern.version.md) | | string | undefined | | ## Methods @@ -60,6 +62,5 @@ export declare class IndexPattern implements IIndexPattern | [prepBody()](./kibana-plugin-plugins-data-public.indexpattern.prepbody.md) | | | | [refreshFields()](./kibana-plugin-plugins-data-public.indexpattern.refreshfields.md) | | | | [removeScriptedField(fieldName)](./kibana-plugin-plugins-data-public.indexpattern.removescriptedfield.md) | | | -| [save(saveAttempts)](./kibana-plugin-plugins-data-public.indexpattern.save.md) | | | | [toSpec()](./kibana-plugin-plugins-data-public.indexpattern.tospec.md) | | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.originalbody.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.originalbody.md new file mode 100644 index 000000000000..4bc3c76afbae --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.originalbody.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPattern](./kibana-plugin-plugins-data-public.indexpattern.md) > [originalBody](./kibana-plugin-plugins-data-public.indexpattern.originalbody.md) + +## IndexPattern.originalBody property + +Signature: + +```typescript +originalBody: { + [key: string]: any; + }; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.removescriptedfield.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.removescriptedfield.md index 42c6dd72b8c4..e902d9c42b08 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.removescriptedfield.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.removescriptedfield.md @@ -7,7 +7,7 @@ Signature: ```typescript -removeScriptedField(fieldName: string): Promise; +removeScriptedField(fieldName: string): void; ``` ## Parameters @@ -18,5 +18,5 @@ removeScriptedField(fieldName: string): Promise; Returns: -`Promise` +`void` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.save.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.save.md deleted file mode 100644 index d0b471cc2bc2..000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.save.md +++ /dev/null @@ -1,22 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPattern](./kibana-plugin-plugins-data-public.indexpattern.md) > [save](./kibana-plugin-plugins-data-public.indexpattern.save.md) - -## IndexPattern.save() method - -Signature: - -```typescript -save(saveAttempts?: number): Promise; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| saveAttempts | number | | - -Returns: - -`Promise` - diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.version.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.version.md new file mode 100644 index 000000000000..99d3bc4e7a04 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.indexpattern.version.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [IndexPattern](./kibana-plugin-plugins-data-public.indexpattern.md) > [version](./kibana-plugin-plugins-data-public.indexpattern.version.md) + +## IndexPattern.version property + +Signature: + +```typescript +version: string | undefined; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md index b651480a8589..0c493ca49295 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md @@ -69,6 +69,7 @@ | [OptionedValueProp](./kibana-plugin-plugins-data-public.optionedvalueprop.md) | | | [Query](./kibana-plugin-plugins-data-public.query.md) | | | [QueryState](./kibana-plugin-plugins-data-public.querystate.md) | All query state service state | +| [QueryStateChange](./kibana-plugin-plugins-data-public.querystatechange.md) | | | [QuerySuggestionBasic](./kibana-plugin-plugins-data-public.querysuggestionbasic.md) | \* | | [QuerySuggestionField](./kibana-plugin-plugins-data-public.querysuggestionfield.md) | \* | | [QuerySuggestionGetFnArgs](./kibana-plugin-plugins-data-public.querysuggestiongetfnargs.md) | \* | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystatechange.appfilters.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystatechange.appfilters.md new file mode 100644 index 000000000000..b358e9477e51 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystatechange.appfilters.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [QueryStateChange](./kibana-plugin-plugins-data-public.querystatechange.md) > [appFilters](./kibana-plugin-plugins-data-public.querystatechange.appfilters.md) + +## QueryStateChange.appFilters property + +Signature: + +```typescript +appFilters?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystatechange.globalfilters.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystatechange.globalfilters.md new file mode 100644 index 000000000000..c395f169c35a --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystatechange.globalfilters.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [QueryStateChange](./kibana-plugin-plugins-data-public.querystatechange.md) > [globalFilters](./kibana-plugin-plugins-data-public.querystatechange.globalfilters.md) + +## QueryStateChange.globalFilters property + +Signature: + +```typescript +globalFilters?: boolean; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystatechange.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystatechange.md new file mode 100644 index 000000000000..71fb211da11d --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystatechange.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [QueryStateChange](./kibana-plugin-plugins-data-public.querystatechange.md) + +## QueryStateChange interface + +Signature: + +```typescript +export interface QueryStateChange extends QueryStateChangePartial +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [appFilters](./kibana-plugin-plugins-data-public.querystatechange.appfilters.md) | boolean | | +| [globalFilters](./kibana-plugin-plugins-data-public.querystatechange.globalfilters.md) | boolean | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md index 9f3ed8c1263b..3dbfd9430e91 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.querystringinput.md @@ -7,5 +7,5 @@ Signature: ```typescript -QueryStringInput: React.FC> +QueryStringInput: React.FC> ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md index 498691c06285..d1d20291a679 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchbar.md @@ -7,7 +7,7 @@ Signature: ```typescript -SearchBar: React.ComponentClass, "query" | "isLoading" | "filters" | "onRefresh" | "onRefreshChange" | "refreshInterval" | "indexPatterns" | "dataTestSubj" | "customSubmitButton" | "screenTitle" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "indicateNoData" | "timeHistory" | "onFiltersUpdated">, any> & { - WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; +SearchBar: React.ComponentClass, "query" | "isLoading" | "filters" | "onRefresh" | "onRefreshChange" | "refreshInterval" | "indexPatterns" | "dataTestSubj" | "timeHistory" | "customSubmitButton" | "screenTitle" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "indicateNoData" | "onFiltersUpdated">, any> & { + WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; } ``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor._constructor_.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor._constructor_.md index 6f5dd1076fb4..4c6763930088 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor._constructor_.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor._constructor_.md @@ -4,12 +4,12 @@ ## SearchInterceptor.(constructor) -This class should be instantiated with a `requestTimeout` corresponding with how many ms after requests are initiated that they should automatically cancel. +Constructs a new instance of the `SearchInterceptor` class Signature: ```typescript -constructor(deps: SearchInterceptorDeps, requestTimeout?: number | undefined); +constructor(deps: SearchInterceptorDeps); ``` ## Parameters @@ -17,5 +17,4 @@ constructor(deps: SearchInterceptorDeps, requestTimeout?: number | undefined); | Parameter | Type | Description | | --- | --- | --- | | deps | SearchInterceptorDeps | | -| requestTimeout | number | undefined | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md index 32954927504a..fd9f23a7f005 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.md @@ -14,21 +14,18 @@ export declare class SearchInterceptor | Constructor | Modifiers | Description | | --- | --- | --- | -| [(constructor)(deps, requestTimeout)](./kibana-plugin-plugins-data-public.searchinterceptor._constructor_.md) | | This class should be instantiated with a requestTimeout corresponding with how many ms after requests are initiated that they should automatically cancel. | +| [(constructor)(deps)](./kibana-plugin-plugins-data-public.searchinterceptor._constructor_.md) | | Constructs a new instance of the SearchInterceptor class | ## Properties | Property | Modifiers | Type | Description | | --- | --- | --- | --- | | [deps](./kibana-plugin-plugins-data-public.searchinterceptor.deps.md) | | SearchInterceptorDeps | | -| [requestTimeout](./kibana-plugin-plugins-data-public.searchinterceptor.requesttimeout.md) | | number | undefined | | ## Methods | Method | Modifiers | Description | | --- | --- | --- | | [getPendingCount$()](./kibana-plugin-plugins-data-public.searchinterceptor.getpendingcount_.md) | | Returns an Observable over the current number of pending searches. This could mean that one of the search requests is still in flight, or that it has only received partial responses. | -| [runSearch(request, signal, strategy)](./kibana-plugin-plugins-data-public.searchinterceptor.runsearch.md) | | | | [search(request, options)](./kibana-plugin-plugins-data-public.searchinterceptor.search.md) | | Searches using the given search method. Overrides the AbortSignal with one that will abort either when cancelPending is called, when the request times out, or when the original AbortSignal is aborted. Updates pendingCount$ when the request is started/finalized. | -| [setupTimers(options)](./kibana-plugin-plugins-data-public.searchinterceptor.setuptimers.md) | | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.requesttimeout.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.requesttimeout.md deleted file mode 100644 index 312343376299..000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.requesttimeout.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptor](./kibana-plugin-plugins-data-public.searchinterceptor.md) > [requestTimeout](./kibana-plugin-plugins-data-public.searchinterceptor.requesttimeout.md) - -## SearchInterceptor.requestTimeout property - -Signature: - -```typescript -protected readonly requestTimeout?: number | undefined; -``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.runsearch.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.runsearch.md deleted file mode 100644 index ad1d1dcb59d7..000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.runsearch.md +++ /dev/null @@ -1,24 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptor](./kibana-plugin-plugins-data-public.searchinterceptor.md) > [runSearch](./kibana-plugin-plugins-data-public.searchinterceptor.runsearch.md) - -## SearchInterceptor.runSearch() method - -Signature: - -```typescript -protected runSearch(request: IEsSearchRequest, signal: AbortSignal, strategy?: string): Observable; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| request | IEsSearchRequest | | -| signal | AbortSignal | | -| strategy | string | | - -Returns: - -`Observable` - diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.setuptimers.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.setuptimers.md deleted file mode 100644 index fe35655258b4..000000000000 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.searchinterceptor.setuptimers.md +++ /dev/null @@ -1,28 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [SearchInterceptor](./kibana-plugin-plugins-data-public.searchinterceptor.md) > [setupTimers](./kibana-plugin-plugins-data-public.searchinterceptor.setuptimers.md) - -## SearchInterceptor.setupTimers() method - -Signature: - -```typescript -protected setupTimers(options?: ISearchOptions): { - combinedSignal: AbortSignal; - cleanup: () => void; - }; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| options | ISearchOptions | | - -Returns: - -`{ - combinedSignal: AbortSignal; - cleanup: () => void; - }` - diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ui_settings.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ui_settings.md index e515c3513df6..6ed20beb396f 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ui_settings.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.ui_settings.md @@ -20,6 +20,7 @@ UI_SETTINGS: { readonly COURIER_MAX_CONCURRENT_SHARD_REQUESTS: "courier:maxConcurrentShardRequests"; readonly COURIER_BATCH_SEARCHES: "courier:batchSearches"; readonly SEARCH_INCLUDE_FROZEN: "search:includeFrozen"; + readonly SEARCH_TIMEOUT: "search:timeout"; readonly HISTOGRAM_BAR_TARGET: "histogram:barTarget"; readonly HISTOGRAM_MAX_BARS: "histogram:maxBars"; readonly HISTORY_LIMIT: "history:limit"; diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.getdefaultsearchparams.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.getdefaultsearchparams.md index 9de005c1fd0d..e718ca42ca30 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.getdefaultsearchparams.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.getdefaultsearchparams.md @@ -7,24 +7,26 @@ Signature: ```typescript -export declare function getDefaultSearchParams(config: SharedGlobalConfig): { - timeout: string; +export declare function getDefaultSearchParams(uiSettingsClient: IUiSettingsClient): Promise<{ + maxConcurrentShardRequests: number | undefined; + ignoreThrottled: boolean; ignoreUnavailable: boolean; - restTotalHitsAsInt: boolean; -}; + trackTotalHits: boolean; +}>; ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| config | SharedGlobalConfig | | +| uiSettingsClient | IUiSettingsClient | | Returns: -`{ - timeout: string; +`Promise<{ + maxConcurrentShardRequests: number | undefined; + ignoreThrottled: boolean; ignoreUnavailable: boolean; - restTotalHitsAsInt: boolean; -}` + trackTotalHits: boolean; +}>` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.getshardtimeout.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.getshardtimeout.md new file mode 100644 index 000000000000..d7e2a597ff33 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.getshardtimeout.md @@ -0,0 +1,30 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [getShardTimeout](./kibana-plugin-plugins-data-server.getshardtimeout.md) + +## getShardTimeout() function + +Signature: + +```typescript +export declare function getShardTimeout(config: SharedGlobalConfig): { + timeout: string; +} | { + timeout?: undefined; +}; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| config | SharedGlobalConfig | | + +Returns: + +`{ + timeout: string; +} | { + timeout?: undefined; +}` + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md index 70c32adeab9f..f5b587d86b34 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md @@ -26,11 +26,13 @@ | Function | Description | | --- | --- | -| [getDefaultSearchParams(config)](./kibana-plugin-plugins-data-server.getdefaultsearchparams.md) | | +| [getDefaultSearchParams(uiSettingsClient)](./kibana-plugin-plugins-data-server.getdefaultsearchparams.md) | | +| [getShardTimeout(config)](./kibana-plugin-plugins-data-server.getshardtimeout.md) | | | [getTime(indexPattern, timeRange, options)](./kibana-plugin-plugins-data-server.gettime.md) | | | [parseInterval(interval)](./kibana-plugin-plugins-data-server.parseinterval.md) | | | [plugin(initializerContext)](./kibana-plugin-plugins-data-server.plugin.md) | Static code to be shared externally | | [shouldReadFieldFromDocValues(aggregatable, esType)](./kibana-plugin-plugins-data-server.shouldreadfieldfromdocvalues.md) | | +| [toSnakeCase(obj)](./kibana-plugin-plugins-data-server.tosnakecase.md) | | | [usageProvider(core)](./kibana-plugin-plugins-data-server.usageprovider.md) | | ## Interfaces diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md index 2d9104ef894b..455c5ecdd819 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md @@ -8,7 +8,7 @@ ```typescript start(core: CoreStart): { - search: ISearchStart>; + search: ISearchStart>; fieldFormats: { fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; @@ -27,7 +27,7 @@ start(core: CoreStart): { Returns: `{ - search: ISearchStart>; + search: ISearchStart>; fieldFormats: { fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tosnakecase.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tosnakecase.md new file mode 100644 index 000000000000..eda9e9c312e5 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tosnakecase.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [toSnakeCase](./kibana-plugin-plugins-data-server.tosnakecase.md) + +## toSnakeCase() function + +Signature: + +```typescript +export declare function toSnakeCase(obj: Record): import("lodash").Dictionary; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| obj | Record<string, any> | | + +Returns: + +`import("lodash").Dictionary` + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ui_settings.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ui_settings.md index e419b64cd43a..2d4ce75b956d 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ui_settings.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.ui_settings.md @@ -20,6 +20,7 @@ UI_SETTINGS: { readonly COURIER_MAX_CONCURRENT_SHARD_REQUESTS: "courier:maxConcurrentShardRequests"; readonly COURIER_BATCH_SEARCHES: "courier:batchSearches"; readonly SEARCH_INCLUDE_FROZEN: "search:includeFrozen"; + readonly SEARCH_TIMEOUT: "search:timeout"; readonly HISTOGRAM_BAR_TARGET: "histogram:barTarget"; readonly HISTOGRAM_MAX_BARS: "histogram:maxBars"; readonly HISTORY_LIMIT: "history:limit"; diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index a64a0330ae43..ed20166c87f2 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -225,6 +225,7 @@ be inconsistent because different shards might be in different refresh states. `search:includeFrozen`:: Includes {ref}/frozen-indices.html[frozen indices] in results. Searching through frozen indices might increase the search time. This setting is off by default. Users must opt-in to include frozen indices. +`search:timeout`:: Change the maximum timeout for a search session or set to 0 to disable the timeout and allow queries to run to completion. [float] [[kibana-siem-settings]] diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 4a931aabd364..f03022e9e9f0 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -20,12 +20,12 @@ which may cause a delay before pages start being served. Set to `false` to disable Console. *Default: `true`* | `cpu.cgroup.path.override:` - | Override for cgroup cpu path when mounted in a -manner that is inconsistent with `/proc/self/cgroup`. + | *deprecated* This setting has been renamed to `ops.cGroupOverrides.cpuPath` +and the old name will no longer be supported as of 8.0. | `cpuacct.cgroup.path.override:` - | Override for cgroup cpuacct path when mounted -in a manner that is inconsistent with `/proc/self/cgroup`. + | *deprecated* This setting has been renamed to `ops.cGroupOverrides.cpuAcctPath` +and the old name will no longer be supported as of 8.0. | `csp.rules:` | A https://w3c.github.io/webappsec-csp/[content-security-policy] template @@ -438,6 +438,14 @@ not saved in {es}. *Default: `data`* | Set the interval in milliseconds to sample system and process performance metrics. The minimum value is 100. *Default: `5000`* +| `ops.cGroupOverrides.cpuPath:` + | Override for cgroup cpu path when mounted in a +manner that is inconsistent with `/proc/self/cgroup`. + +| `ops.cGroupOverrides.cpuAcctPath:` + | Override for cgroup cpuacct path when mounted +in a manner that is inconsistent with `/proc/self/cgroup`. + | `server.basePath:` | Enables you to specify a path to mount {kib} at if you are running behind a proxy. Use the `server.rewriteBasePath` setting to tell {kib} diff --git a/docs/user/dashboard/dashboard-drilldown.asciidoc b/docs/user/dashboard/dashboard-drilldown.asciidoc new file mode 100644 index 000000000000..84701cae2ecc --- /dev/null +++ b/docs/user/dashboard/dashboard-drilldown.asciidoc @@ -0,0 +1,76 @@ +[[dashboard-drilldown]] +=== Dashboard drilldown + +The dashboard drilldown allows you to navigate from one dashboard to another dashboard. +For example, you might have a dashboard that shows the overall status of multiple data centers. +You can create a drilldown that navigates from this dashboard to a dashboard +that shows a single data center or server. + +This example shows a dashboard panel that contains a pie chart with a configured dashboard drilldown: + +[role="screenshot"] +image::images/drilldown_on_piechart.gif[Drilldown on pie chart that navigates to another dashboard] + +[float] +[[drilldowns-example]] +==== Try it: Create a dashboard drilldown + +Create the *Host Overview* drilldown shown above. + +*Set up the dashboards* + +. Add the <> data set. + +. Create a new dashboard, called `Host Overview`, and include these visualizations +from the sample data set: ++ +[%hardbreaks] +*[Logs] Heatmap* +*[Logs] Visitors by OS* +*[Logs] Host, Visits, and Bytes Table* +*[Logs] Total Requests and Bytes* ++ +TIP: If you don’t see data for a panel, try changing the time range. + +. Open the *[Logs] Web traffic* dashboard. + +. Set a search and filter. ++ +[%hardbreaks] +Search: `extension.keyword:( “gz” or “css” or “deb”)` +Filter: `geo.src : CN` + + +*Create the drilldown* + + +. In the dashboard menu bar, click *Edit*. + +. In *[Logs] Visitors by OS*, open the panel menu, and then select *Create drilldown*. + +. Pick *Go to dashboard* action. + +. Give the drilldown a name. + +. Select *Host Overview* as the destination dashboard. + +. Keep both filters enabled so that the drilldown carries over the global filters and date range. ++ +Your input should look similar to this: ++ +[role="screenshot"] +image::images/drilldown_create.png[Create drilldown with entries for drilldown name and destination] + +. Click *Create drilldown.* + +. Save the dashboard. ++ +If you don’t save the drilldown, and then navigate away, the drilldown is lost. + +. In *[Logs] Visitors by OS*, click the `win 8` slice of the pie, and then select the name of your drilldown. ++ +[role="screenshot"] +image::images/drilldown_on_panel.png[Drilldown on pie chart that navigates to another dashboard] ++ +You are navigated to your destination dashboard. Verify that the search query, filters, +and time range are carried over. diff --git a/docs/user/dashboard/dashboard.asciidoc b/docs/user/dashboard/dashboard.asciidoc index 0c0151cc3ace..c8bff91be91a 100644 --- a/docs/user/dashboard/dashboard.asciidoc +++ b/docs/user/dashboard/dashboard.asciidoc @@ -4,9 +4,9 @@ [partintro] -- -A _dashboard_ is a collection of panels that you use to analyze your data. On a dashboard, you can add a variety of panels that -you can rearrange and tell a story about your data. Panels contain everything you need, including visualizations, -interactive controls, markdown, and more. +A _dashboard_ is a collection of panels that you use to analyze your data. On a dashboard, you can add a variety of panels that +you can rearrange and tell a story about your data. Panels contain everything you need, including visualizations, +interactive controls, markdown, and more. With *Dashboard*s, you can: @@ -18,7 +18,7 @@ With *Dashboard*s, you can: * Create and apply filters to focus on the data you want to display. -* Control who can use your data, and share the dashboard with a small or large audience. +* Control who can use your data, and share the dashboard with a small or large audience. * Generate reports based on your findings. @@ -42,7 +42,7 @@ image::images/dashboard-read-only-badge.png[Example of Dashboard read only acces [[types-of-panels]] == Types of panels -Panels contain everything you need to tell a story about you data, including visualizations, +Panels contain everything you need to tell a story about you data, including visualizations, interactive controls, Markdown, and more. [cols="50, 50"] @@ -50,30 +50,30 @@ interactive controls, Markdown, and more. a| *Area* -Displays data points, connected by a line, where the area between the line and axes are shaded. +Displays data points, connected by a line, where the area between the line and axes are shaded. Use area charts to compare two or more categories over time, and display the magnitude of trends. | image:images/area.png[Area chart] a| *Stacked area* -Displays the evolution of the value of several data groups. The values of each group are displayed -on top of each other. Use stacked area charts to visualize part-to-whole relationships, and to show +Displays the evolution of the value of several data groups. The values of each group are displayed +on top of each other. Use stacked area charts to visualize part-to-whole relationships, and to show how each category contributes to the cumulative total. | image:images/stacked_area.png[Stacked area chart] a| *Bar* -Displays bars side-by-side where each bar represents a category. Use bar charts to compare data across a -large number of categories, display data that includes categories with negative values, and easily identify +Displays bars side-by-side where each bar represents a category. Use bar charts to compare data across a +large number of categories, display data that includes categories with negative values, and easily identify the categories that represent the highest and lowest values. Kibana also supports horizontal bar charts. | image:images/bar.png[Bar chart] a| *Stacked bar* -Displays numeric values across two or more categories. Use stacked bar charts to compare numeric values between +Displays numeric values across two or more categories. Use stacked bar charts to compare numeric values between levels of a categorical value. Kibana also supports stacked horizontal bar charts. | image:images/stacked_bar.png[Stacked area chart] @@ -81,15 +81,15 @@ levels of a categorical value. Kibana also supports stacked horizontal bar chart a| *Line* -Displays data points that are connected by a line. Use line charts to visualize a sequence of values, discover +Displays data points that are connected by a line. Use line charts to visualize a sequence of values, discover trends over time, and forecast future values. | image:images/line.png[Line chart] a| *Pie* -Displays slices that represent a data category, where the slice size is proportional to the quantity it represents. -Use pie charts to show comparisons between multiple categories, illustrate the dominance of one category over others, +Displays slices that represent a data category, where the slice size is proportional to the quantity it represents. +Use pie charts to show comparisons between multiple categories, illustrate the dominance of one category over others, and show percentage or proportional data. | image:images/pie.png[Pie chart] @@ -103,7 +103,7 @@ Similar to the pie chart, but the central circle is removed. Use donut charts wh a| *Tree map* -Relates different segments of your data to the whole. Each rectangle is subdivided into smaller rectangles, or sub branches, based on +Relates different segments of your data to the whole. Each rectangle is subdivided into smaller rectangles, or sub branches, based on its proportion to the whole. Use treemaps to make efficient use of space to show percent total for each category. | image:images/treemap.png[Tree map] @@ -111,7 +111,7 @@ its proportion to the whole. Use treemaps to make efficient use of space to show a| *Heat map* -Displays graphical representations of data where the individual values are represented by colors. Use heat maps when your data set includes +Displays graphical representations of data where the individual values are represented by colors. Use heat maps when your data set includes categorical data. For example, use a heat map to see the flights of origin countries compared to destination countries using the sample flight data. | image:images/heat_map.png[Heat map] @@ -125,7 +125,7 @@ Displays how your metric progresses toward a fixed goal. Use the goal to display a| *Gauge* -Displays your data along a scale that changes color according to where your data falls on the expected scale. Use the gauge to show how metric +Displays your data along a scale that changes color according to where your data falls on the expected scale. Use the gauge to show how metric values relate to reference threshold values, or determine how a specified field is performing versus how it is expected to perform. | image:images/gauge.png[Gauge] @@ -133,7 +133,7 @@ values relate to reference threshold values, or determine how a specified field a| *Metric* -Displays a single numeric value for an aggregation. Use the metric visualization when you have a numeric value that is powerful enough to tell +Displays a single numeric value for an aggregation. Use the metric visualization when you have a numeric value that is powerful enough to tell a story about your data. | image:images/metric.png[Metric] @@ -141,7 +141,7 @@ a story about your data. a| *Data table* -Displays your raw data or aggregation results in a tabular format. Use data tables to display server configuration details, track counts, min, +Displays your raw data or aggregation results in a tabular format. Use data tables to display server configuration details, track counts, min, or max values for a specific field, and monitor the status of key services. | image:images/data_table.png[Data table] @@ -149,7 +149,7 @@ or max values for a specific field, and monitor the status of key services. a| *Tag cloud* -Graphical representations of how frequently a word appears in the source text. Use tag clouds to easily produce a summary of large documents and +Graphical representations of how frequently a word appears in the source text. Use tag clouds to easily produce a summary of large documents and create visual art for a specific topic. | image:images/tag_cloud.png[Tag cloud] @@ -168,16 +168,16 @@ For all your mapping needs, use <>. [[create-panels]] == Create panels -To create a panel, make sure you have {ref}/getting-started-index.html[data indexed into {es}] and an <> -to retrieve the data from {es}. If you aren’t ready to use your own data, {kib} comes with several pre-built dashboards that you can test out. For more information, +To create a panel, make sure you have {ref}/getting-started-index.html[data indexed into {es}] and an <> +to retrieve the data from {es}. If you aren’t ready to use your own data, {kib} comes with several pre-built dashboards that you can test out. For more information, refer to <>. -To begin, click *Create new*, then choose one of the following options on the +To begin, click *Create new*, then choose one of the following options on the *New Visualization* window: -* Click on the type of panel you want to create, then configure the options. +* Click on the type of panel you want to create, then configure the options. -* Select an editor to help you create the panel. +* Select an editor to help you create the panel. [role="screenshot"] image:images/Dashboard_add_new_visualization.png[Example add new visualization to dashboard] @@ -188,19 +188,19 @@ image:images/Dashboard_add_new_visualization.png[Example add new visualization t [[lens]] === Create panels with Lens -*Lens* is the simplest and fastest way to create powerful visualizations of your data. To use *Lens*, you drag and drop as many data fields +*Lens* is the simplest and fastest way to create powerful visualizations of your data. To use *Lens*, you drag and drop as many data fields as you want onto the visualization builder pane, and *Lens* uses heuristics to decide how to apply each field to the visualization. With *Lens*, you can: * Use the automatically generated suggestions to change the visualization type. -* Create visualizations with multiple layers and indices. +* Create visualizations with multiple layers and indices. * Change the aggregation and labels to customize the data. [role="screenshot"] image::images/lens_drag_drop.gif[Drag and drop] -TIP: Drag-and-drop capabilities are available only when *Lens* knows how to use the data. If *Lens* is unable to automatically generate a +TIP: Drag-and-drop capabilities are available only when *Lens* knows how to use the data. If *Lens* is unable to automatically generate a visualization, configure the customization options for your visualization. [float] @@ -220,7 +220,7 @@ To filter the data fields: [[view-data-summaries]] ==== View data summaries -To help you decide exactly the data you want to display, get a quick summary of each field. The summary shows the distribution of +To help you decide exactly the data you want to display, get a quick summary of each field. The summary shows the distribution of values within the specified time range. To view the data field summary information, navigate to the field, then click *i*. @@ -250,10 +250,10 @@ When there is an exclamation point (!) next to a visualization type, *Lens* is u [[customize-the-data]] ==== Customize the data -For each visualization type, you can customize the aggregation and labels. The options available depend on the selected visualization type. +For each visualization type, you can customize the aggregation and labels. The options available depend on the selected visualization type. . Click a data field name in the editor, or click *Drop a field here*. -. Change the options that appear. +. Change the options that appear. + [role="screenshot"] image::images/lens_aggregation_labels.png[Quick function options] @@ -262,7 +262,7 @@ image::images/lens_aggregation_labels.png[Quick function options] [[add-layers-and-indices]] ==== Add layers and indices -To compare and analyze data from different sources, you can visualize multiple data layers and indices. Multiple layers and indices are +To compare and analyze data from different sources, you can visualize multiple data layers and indices. Multiple layers and indices are supported in area, line, and bar charts. To add a layer, click *+*, then drag and drop the data fields for the new layer. @@ -281,7 +281,7 @@ Ready to try out *Lens*? Refer to the <>. [[tsvb]] === Create panels with TSVB -*TSVB* is a time series data visualizer that allows you to use the full power of the Elasticsearch aggregation framework. To use *TSVB*, +*TSVB* is a time series data visualizer that allows you to use the full power of the Elasticsearch aggregation framework. To use *TSVB*, you can combine an infinite number of <> to display your data. With *TSVB*, you can: @@ -295,15 +295,15 @@ image::images/tsvb.png[TSVB UI] [float] [[configure-the-data]] -==== Configure the data +==== Configure the data -With *TSVB*, you can add and display multiple data sets to compare and analyze. {kib} uses many types of <> that you can use to build +With *TSVB*, you can add and display multiple data sets to compare and analyze. {kib} uses many types of <> that you can use to build complex summaries of that data. . Select *Data*. If you are using *Table*, select *Columns*. -. From the *Aggregation* drop down, select the aggregation you want to visualize. +. From the *Aggregation* drop down, select the aggregation you want to visualize. + -If you don’t see any data, change the <>. +If you don’t see any data, change the <>. + To add multiple aggregations, click *+*. . From the *Group by* drop down, select how you want to group or split the data. @@ -315,14 +315,14 @@ When you have more than one aggregation, the last value is displayed, which is i [[change-the-data-display]] ==== Change the data display -To find the best way to display your data, *TSVB* supports several types of panels and charts. +To find the best way to display your data, *TSVB* supports several types of panels and charts. To change the *Time Series* chart type: . Click *Data > Options*. . Select the *Chart type*. -To change the panel type, click on the panel options: +To change the panel type, click on the panel options: [role="screenshot"] image::images/tsvb_change_display.gif[TSVB change the panel type] @@ -331,7 +331,7 @@ image::images/tsvb_change_display.gif[TSVB change the panel type] [[custommize-the-data]] ==== Customize the data -View data in a different <>, and change the data label name and colors. The options available depend on the panel type. +View data in a different <>, and change the data label name and colors. The options available depend on the panel type. To change the index pattern, click *Panel options*, then enter the new *Index Pattern*. @@ -361,7 +361,7 @@ image::images/tsvb_annotations.png[TSVB annotations] [[filter-the-panel]] ==== Filter the panel -The data that displays on the panel is based on the <> and <>. +The data that displays on the panel is based on the <> and <>. You can filter the data on the panels using the <>. Click *Panel options*, then enter the syntax in the *Panel Filter* field. @@ -372,7 +372,7 @@ If you want to ignore filters from all of {kib}, select *Yes* for *Ignore global [[vega]] === Create custom panels with Vega -Build custom visualizations using *Vega* and *Vega-Lite*, backed by one or more data sources including {es}, Elastic Map Service, +Build custom visualizations using *Vega* and *Vega-Lite*, backed by one or more data sources including {es}, Elastic Map Service, URL, or static data. Use the {kib} extensions to embed *Vega* in your dashboard, and add interactive tools. Use *Vega* and *Vega-Lite* when you want to create a visualization for: @@ -405,7 +405,7 @@ For more information about *Vega* and *Vega-Lite*, refer to: [[timelion]] === Create panels with Timelion -*Timelion* is a time series data visualizer that enables you to combine independent data sources within a single visualization. +*Timelion* is a time series data visualizer that enables you to combine independent data sources within a single visualization. *Timelion* is driven by a simple expression language that you use to: @@ -422,9 +422,41 @@ Ready to try out Timelion? For step-by-step tutorials, refer to: * <> * <> +[float] +[[timelion-deprecation]] +==== Timelion app deprecation + +Deprecated since 7.0, the Timelion app will be removed in 8.0. If you have any Timelion worksheets, you must migrate them to a dashboard. + +NOTE: Only the Timelion app is deprecated. {kib} continues to support Timelion +visualizations on dashboards and in Visualize and Canvas. + +To migrate a Timelion worksheet to a dashboard: + +. Open the menu, click **Dashboard**, then click **Create dashboard**. + +. On the dashboard, click **Create New**, then select the Timelion visualization. + +. On a new tab, open the Timelion app, select the chart you want to copy, and copy its expression. ++ +[role="screenshot"] +image::images/timelion-copy-expression.png[] + +. Return to the other tab and paste the copied expression to the *Timelion Expression* field and click **Update**. ++ +[role="screenshot"] +image::images/timelion-vis-paste-expression.png[] + +. Save the new visualization, give it a name, and click **Save and Return**. ++ +Your Timelion visualization will appear on the dashboard. Repeat this for all your charts on each worksheet. ++ +[role="screenshot"] +image::images/timelion-dashboard.png[] + [float] [[save-panels]] -=== Save panels +== Save panels When you’ve finished making changes, save the panels. @@ -436,7 +468,7 @@ When you’ve finished making changes, save the panels. [[add-existing-panels]] == Add existing panels -Add panels that you’ve already created to your dashboard. +Add panels that you’ve already created to your dashboard. On the dashboard, click *Add an existing*, then select the panel you want to add. @@ -445,7 +477,7 @@ When a panel contains a stored query, both queries are applied. [role="screenshot"] image:images/Dashboard_add_visualization.png[Example add visualization to dashboard] -To make changes to the panel, put the dashboard in *Edit* mode, then select the edit option from the panel menu. +To make changes to the panel, put the dashboard in *Edit* mode, then select the edit option from the panel menu. The changes you make appear in every dashboard that uses the panel, except if you edit the panel title. Changes to the panel title appear only on the dashboard where you made the change. [float] @@ -463,6 +495,8 @@ include::edit-dashboards.asciidoc[] include::explore-dashboard-data.asciidoc[] +include::drilldowns.asciidoc[] + include::share-dashboards.asciidoc[] include::tutorials.asciidoc[] diff --git a/docs/user/dashboard/drilldowns.asciidoc b/docs/user/dashboard/drilldowns.asciidoc index 5fca974d5813..85230f1b6f70 100644 --- a/docs/user/dashboard/drilldowns.asciidoc +++ b/docs/user/dashboard/drilldowns.asciidoc @@ -1,106 +1,51 @@ -[float] [[drilldowns]] -=== Use drilldowns for dashboard actions +== Use drilldowns for dashboard actions Drilldowns, also known as custom actions, allow you to configure a workflow for analyzing and troubleshooting your data. -Using a drilldown, you can navigate from one dashboard to another, +For example, using a drilldown, you can navigate from one dashboard to another, taking the current time range, filters, and other parameters with you, so the context remains the same. You can continue your analysis from a new perspective. -For example, you might have a dashboard that shows the overall status of multiple data centers. -You can create a drilldown that navigates from this dashboard to a dashboard -that shows a single data center or server. - -[float] -[[how-drilldowns-work]] -==== How drilldowns work - -Drilldowns are user-configurable {kib} actions that are stored with the -dashboard metadata. Drilldowns are specific to the dashboard panel -for which you create them—they are not shared across panels. -A panel can have multiple drilldowns. - -This example shows a dashboard panel that contains a pie chart. -Typically, clicking a pie slice applies the current filter. -When a panel has a drilldown, clicking a pie slice opens a menu with -the default action and your drilldowns. Refer to the <> -for instructions on how to create this drilldown. - [role="screenshot"] image::images/drilldown_on_piechart.gif[Drilldown on pie chart that navigates to another dashboard] -Third-party developers can create drilldowns. -Refer to https://github.com/elastic/kibana/tree/master/x-pack/examples/ui_actions_enhanced_examples[this example plugin] -to learn how to code drilldowns. - -[float] -[[create-manage-drilldowns]] -==== Create and manage drilldowns - -Your dashboard must be in *Edit* mode to create a drilldown. -Once a panel has at least one drilldown, the menu also includes a *Manage drilldowns* action -for editing and deleting drilldowns. - -[role="screenshot"] -image::images/drilldown_menu.png[Panel menu with Create drilldown and Manage drilldown actions] +Drilldowns are specific to the dashboard panel for which you create them—they are not shared across panels. A panel can have multiple drilldowns. [float] -[[drilldowns-example]] -==== Try it: Create a drilldown - -This example shows how to create the *Host Overview* drilldown shown earlier in this doc. +[[actions]] +=== Drilldown actions -*Set up the dashboards* +Drilldowns are user-configurable {kib} actions that are stored with the dashboard metadata. +Kibana provides the following types of actions: -. Add the <> data set. +[cols="2"] +|=== -. Create a new dashboard, called `Host Overview`, and include these visualizations -from the sample data set: -+ -[%hardbreaks] -*[Logs] Heatmap* -*[Logs] Visitors by OS* -*[Logs] Host, Visits, and Bytes Table* -*[Logs] Total Requests and Bytes* -+ -TIP: If you don’t see data for a panel, try changing the time range. +a| <> -. Open the *[Logs] Web traffic* dashboard. +| Navigate to a dashboard. -. Set a search and filter. -+ -[%hardbreaks] -Search: `extension.keyword:( “gz” or “css” or “deb”)` -Filter: `geo.src : CN` +a| <> -*Create the drilldown* +| Navigate to external or internal URL. -. In the dashboard menu bar, click *Edit*. +|=== -. In *[Logs] Visitors by OS*, open the panel menu, and then select *Create drilldown*. +[NOTE] +============================================== +Some action types are paid commercial features, while others are free. +For a comparison of the Elastic subscription levels, +see https://www.elastic.co/subscriptions[the subscription page]. +============================================== -. Give the drilldown a name. - -. Select *Host Overview* as the destination dashboard. - -. Keep both filters enabled so that the drilldown carries over the global filters and date range. -+ -Your input should look similar to this: -+ -[role="screenshot"] -image::images/drilldown_create.png[Create drilldown with entries for drilldown name and destination] - -. Click *Create drilldown.* +[float] +[[code-drilldowns]] +=== Code drilldowns +Third-party developers can create drilldowns. +Refer to {kib-repo}blob/{branch}/x-pack/examples/ui_actions_enhanced_examples[this example plugin] +to learn how to code drilldowns. -. Save the dashboard. -+ -If you don’t save the drilldown, and then navigate away, the drilldown is lost. +include::dashboard-drilldown.asciidoc[] +include::url-drilldown.asciidoc[] -. In *[Logs] Visitors by OS*, click the `win 8` slice of the pie, and then select the name of your drilldown. -+ -[role="screenshot"] -image::images/drilldown_on_panel.png[Drilldown on pie chart that navigates to another dashboard] -+ -You are navigated to your destination dashboard. Verify that the search query, filters, -and time range are carried over. diff --git a/docs/user/dashboard/explore-dashboard-data.asciidoc b/docs/user/dashboard/explore-dashboard-data.asciidoc index a0564f5bceb3..238dfb79e900 100644 --- a/docs/user/dashboard/explore-dashboard-data.asciidoc +++ b/docs/user/dashboard/explore-dashboard-data.asciidoc @@ -16,5 +16,3 @@ The data that displays depends on the element that you inspect. image:images/Dashboard_inspect.png[Inspect in dashboard] include::explore-underlying-data.asciidoc[] - -include::drilldowns.asciidoc[] diff --git a/docs/user/dashboard/images/drilldown_pick_an_action.png b/docs/user/dashboard/images/drilldown_pick_an_action.png new file mode 100644 index 000000000000..c99e931e3fbe Binary files /dev/null and b/docs/user/dashboard/images/drilldown_pick_an_action.png differ diff --git a/docs/user/dashboard/images/url_drilldown_github.png b/docs/user/dashboard/images/url_drilldown_github.png new file mode 100644 index 000000000000..d2eaec311948 Binary files /dev/null and b/docs/user/dashboard/images/url_drilldown_github.png differ diff --git a/docs/user/dashboard/images/url_drilldown_go_to_github.gif b/docs/user/dashboard/images/url_drilldown_go_to_github.gif new file mode 100644 index 000000000000..7cca3f72d5a6 Binary files /dev/null and b/docs/user/dashboard/images/url_drilldown_go_to_github.gif differ diff --git a/docs/user/dashboard/images/url_drilldown_pick_an_action.png b/docs/user/dashboard/images/url_drilldown_pick_an_action.png new file mode 100644 index 000000000000..c99e931e3fbe Binary files /dev/null and b/docs/user/dashboard/images/url_drilldown_pick_an_action.png differ diff --git a/docs/user/dashboard/images/url_drilldown_popup.png b/docs/user/dashboard/images/url_drilldown_popup.png new file mode 100644 index 000000000000..392edd16ea32 Binary files /dev/null and b/docs/user/dashboard/images/url_drilldown_popup.png differ diff --git a/docs/user/dashboard/images/url_drilldown_trigger_picker.png b/docs/user/dashboard/images/url_drilldown_trigger_picker.png new file mode 100644 index 000000000000..2fe930f35dce Binary files /dev/null and b/docs/user/dashboard/images/url_drilldown_trigger_picker.png differ diff --git a/docs/user/dashboard/images/url_drilldown_url_template.png b/docs/user/dashboard/images/url_drilldown_url_template.png new file mode 100644 index 000000000000..d8515afe66a8 Binary files /dev/null and b/docs/user/dashboard/images/url_drilldown_url_template.png differ diff --git a/docs/user/dashboard/url-drilldown.asciidoc b/docs/user/dashboard/url-drilldown.asciidoc new file mode 100644 index 000000000000..16f82477756b --- /dev/null +++ b/docs/user/dashboard/url-drilldown.asciidoc @@ -0,0 +1,221 @@ +[[url-drilldown]] +=== URL drilldown + +The URL drilldown allows you to navigate from a dashboard to an internal or external URL. +The destination URL can be dynamic, depending on the dashboard context or user’s interaction with a visualization. + +For example, you might have a dashboard that shows data from a Github repository. +You can create a drilldown that navigates from this dashboard to Github. + +[role="screenshot"] +image:images/url_drilldown_go_to_github.gif[Drilldown on pie chart that navigates to Github] + +NOTE: URL drilldown is available with the https://www.elastic.co/subscriptions[Gold subscription] and higher. + +[float] +[[try-it]] +==== Try it: Create a URL drilldown + +This example shows how to create the "Show on Github" drilldown shown above. + +. Add the <> data set. +. Open the *[Logs] Web traffic* dashboard. This isn’t data from Github, but it should work for demonstration purposes. +. In the dashboard menu bar, click *Edit*. +. In *[Logs] Visitors by OS*, open the panel menu, and then select *Create drilldown*. +. Give the drilldown a name: *Show on Github*. +. Select a drilldown action: *Go to URL*. ++ +[role="screenshot"] +image:images/url_drilldown_pick_an_action.png[Action picker] +. Enter a URL template: ++ +[source, bash] +---- +https://github.com/elastic/kibana/issues?q=is:issue+is:open+{{event.value}} +---- ++ +This example URL navigates to {kib} issues on Github. `{{event.value}}` will be substituted with a value associated with a clicked pie slice. In _preview_ `{{event.value}}` is substituted with a <> value. +[role="screenshot"] +image:images/url_drilldown_url_template.png[URL template input] +. Click *Create drilldown*. +. Save the dashboard. ++ +If you don’t save the drilldown, and then navigate away, the drilldown is lost. + +. In *[Logs] Visitors by OS*, click any slice of the pie, and then select the drilldown *Show on Github*. ++ +[role="screenshot"] +image:images/url_drilldown_popup.png[URL drilldown popup] ++ +You are navigated to the issue list in the {kib} repository. Verify that value from a pie slice you’ve clicked on is carried over to Github. ++ +[role="screenshot"] +image:images/url_drilldown_github.png[Github] + +[float] +[[trigger-picker]] +==== Picking a trigger for a URL drilldown + +Some panels support multiple user interactions (called triggers) for which you can configure a URL drilldown. The list of supported variables in the URL template depends on the trigger you selected. +In the preceding example, you configured a URL drilldown on a pie chart. The only trigger that pie chart supports is clicking on a pie slice, so you didn’t have to pick a trigger. + +However, the sample *[Logs] Unique Visitors vs. Average Bytes* chart supports both clicking on a data point and selecting a range. When you create a URL drilldown for this chart, you have the following choices: + +[role="screenshot"] +image:images/url_drilldown_trigger_picker.png[Trigger picker: Single click and Range selection] + +Variables in the URL template differ per trigger. +For example, *Single click* has `{{event.value}}` and *Range selection* has `{{event.from}}` and `{{event.to}}`. +You can create multiple URL drilldowns per panel and attach them to different triggers. + +[float] +[[templating]] +==== URL templating language + +The URL template input uses Handlebars — a simple templating language. Handlebars templates look like regular text with embedded Handlebars expressions. + +[source, bash] +---- +https://github.com/elastic/kibana/issues?q={{event.value}} +---- + +A Handlebars expression is a `{{`, some contents, followed by a `}}`. When the drilldown is executed, these expressions are replaced by values from the dashboard and interaction context. + +Refer to Handlebars https://handlebarsjs.com/guide/expressions.html#expressions[documentation] to learn about advanced use cases. + +[[helpers]] +In addition to https://handlebarsjs.com/guide/builtin-helpers.html[built-in] Handlebars helpers, you can use the following custom helpers: + + +|=== +|Helper |Use case + +|json +a|Serialize variables in JSON format. + +Example: + +`{{json event}}` + +`{{json event.key event.value}}` + +`{{json filters=context.panel.filters}}` + + +|rison +a|Serialize variables in https://github.com/w33ble/rison-node[rison] format. Rison is a common format for {kib} apps for storing state in the URL. + +Example: + +`{{rison event}}` + +`{{rison event.key event.value}}` + +`{{rison filters=context.panel.filters}}` + + +|date +a|Format dates. Supports relative dates expressions (for example, "now-15d"). Refer to the https://momentjs.com/docs/#/displaying/format/[moment] docs for different formatting options. + +Example: + +`{{ date event.from “YYYY MM DD”}}` + +`{{date “now-15”}}` +|=== + + +[float] +[[variables]] +==== URL template variables + +The URL drilldown template has three sources for variables: + +* *Global* static variables that don’t change depending on the place where the URL drilldown is used or which user interaction executed the drilldown. For example: `{{kibanaUrl}}`. +* *Context* variables that change depending on where the drilldown is created and used. These variables are extracted from a context of a panel on a dashboard. For example, `{{context.panel.filters}}` gives access to filters that applied to the current panel. +* *Event* variables that depend on the trigger context. These variables are dynamically extracted from the interaction context when the drilldown is executed. + +[[values-in-preview]] +A subtle but important difference between *context* and *event* variables is that *context* variables use real values in previews when creating a URL drilldown. +For example, `{{context.panel.filters}}` are previewed with the current filters that applied to a panel. +*Event* variables are extracted during drilldown execution from a user interaction with a panel (for example, from a pie slice that the user clicked on). + +Because there is no user interaction with a panel in preview, there is no interaction context to use in a preview. +To work around this, {kib} provides a sample interaction that relies on a picked <>. +So in a preview, you might notice that `{{event.value}}` is replaced with `{{event.value}}` instead of with a sample from your data. +Such previews can help you make sure that the structure of your URL template is valid. +However, to ensure that the configured URL drilldown works as expected with your data, you have to save the dashboard and test in the panel. + +You can access the full list of variables available for the current panel and selected trigger by clicking *Add variable* in the top-right corner of a URL template input. + +[float] +[[variables-reference]] +==== Variables reference + + +|=== +|Source |Variable |Description + +|*Global* +| kibanaUrl +| {kib} base URL. Useful for creating URL drilldowns that navigate within {kib}. + +| *Context* +| context.panel +| Context provided by current dashboard panel. + +| +| context.panel.id +| ID of a panel. + +| +| context.panel.title +| Title of a panel. + +| +| context.panel.filters +| List of {kib} filters applied to a panel. + +Tip: Use in combination with <> helper for +internal {kib} navigations with carrying over current filters. + +| +| context.panel.query.query +| Current query string. + +| +| context.panel.query.lang +| Current query language. + +| +| context.panel.timeRange.from + +context.panel.timeRange.to +| Current time picker values. + +Tip: Use in combination with <> helper to format date. + +| +| context.panel.timeRange.indexPatternId + +context.panel.timeRange.indexPatternIds +|Index pattern ids used by a panel. + +| +| context.panel.savedObjectId +| ID of saved object behind a panel. + +| *Single click* +| event.value +| Value behind clicked data point. + +| +| event.key +| Field name behind clicked data point + +| +| event.negate +| Boolean, indicating whether clicked data point resulted in negative filter. + +| *Range selection* +| event.from + +event.to +| `from` and `to` values of selected range. Depending on your data, could be either a date or number. + +Tip: Consider using <> helper for date formatting. + +| +| event.key +| Aggregation field behind the selected range, if available. + +|=== diff --git a/docs/user/reporting/reporting-troubleshooting.asciidoc b/docs/user/reporting/reporting-troubleshooting.asciidoc index dc4ffdfebdae..82f0aa7ca0f1 100644 --- a/docs/user/reporting/reporting-troubleshooting.asciidoc +++ b/docs/user/reporting/reporting-troubleshooting.asciidoc @@ -7,6 +7,7 @@ Having trouble? Here are solutions to common problems you might encounter while using Reporting. +* <> * <> * <> * <> @@ -15,6 +16,11 @@ Having trouble? Here are solutions to common problems you might encounter while * <> * <> +[float] +[[reporting-diagnostics]] +=== Reporting Diagnostics +Reporting comes with a built-in utility to try to automatically find common issues. When Kibana is running, navigate to the Report Listing page, and click the "Run reporting diagnostics..." button. This will open up a diagnostic tool that checks various parts of the Kibana deployment to come up with any relevant recommendations. + [float] [[reporting-troubleshooting-system-dependencies]] === System dependencies diff --git a/kibana.d.ts b/kibana.d.ts index d64752abd8b6..517bda374af9 100644 --- a/kibana.d.ts +++ b/kibana.d.ts @@ -39,8 +39,6 @@ export namespace Legacy { export type KibanaConfig = LegacyKibanaServer.KibanaConfig; export type Request = LegacyKibanaServer.Request; export type ResponseToolkit = LegacyKibanaServer.ResponseToolkit; - export type SavedObjectsClient = LegacyKibanaServer.SavedObjectsClient; - export type SavedObjectsService = LegacyKibanaServer.SavedObjectsLegacyService; export type Server = LegacyKibanaServer.Server; export type InitPluginFunction = LegacyKibanaPluginSpec.InitPluginFunction; diff --git a/package.json b/package.json index ff487510f7a3..95a6de337f62 100644 --- a/package.json +++ b/package.json @@ -231,7 +231,7 @@ "@babel/parser": "^7.11.2", "@babel/types": "^7.11.0", "@elastic/apm-rum": "^5.5.0", - "@elastic/charts": "21.0.1", + "@elastic/charts": "21.1.2", "@elastic/ems-client": "7.9.3", "@elastic/eslint-config-kibana": "0.15.0", "@elastic/eslint-plugin-eui": "0.0.2", diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json index 4b2e88d15524..bbe7b1bc2e8d 100644 --- a/packages/kbn-ui-shared-deps/package.json +++ b/packages/kbn-ui-shared-deps/package.json @@ -9,7 +9,7 @@ "kbn:watch": "node scripts/build --dev --watch" }, "dependencies": { - "@elastic/charts": "21.0.1", + "@elastic/charts": "21.1.2", "@elastic/eui": "28.2.0", "@elastic/numeral": "^2.5.0", "@kbn/i18n": "1.0.0", diff --git a/packages/kbn-ui-shared-deps/webpack.config.js b/packages/kbn-ui-shared-deps/webpack.config.js index c81da4689052..fa80dfdeef20 100644 --- a/packages/kbn-ui-shared-deps/webpack.config.js +++ b/packages/kbn-ui-shared-deps/webpack.config.js @@ -32,22 +32,10 @@ exports.getWebpackConfig = ({ dev = false } = {}) => ({ mode: dev ? 'development' : 'production', entry: { 'kbn-ui-shared-deps': './entry.js', - 'kbn-ui-shared-deps.v7.dark': [ - '@elastic/eui/dist/eui_theme_dark.css', - '@elastic/charts/dist/theme_only_dark.css', - ], - 'kbn-ui-shared-deps.v7.light': [ - '@elastic/eui/dist/eui_theme_light.css', - '@elastic/charts/dist/theme_only_light.css', - ], - 'kbn-ui-shared-deps.v8.dark': [ - '@elastic/eui/dist/eui_theme_amsterdam_dark.css', - '@elastic/charts/dist/theme_only_dark.css', - ], - 'kbn-ui-shared-deps.v8.light': [ - '@elastic/eui/dist/eui_theme_amsterdam_light.css', - '@elastic/charts/dist/theme_only_light.css', - ], + 'kbn-ui-shared-deps.v7.dark': ['@elastic/eui/dist/eui_theme_dark.css'], + 'kbn-ui-shared-deps.v7.light': ['@elastic/eui/dist/eui_theme_light.css'], + 'kbn-ui-shared-deps.v8.dark': ['@elastic/eui/dist/eui_theme_amsterdam_dark.css'], + 'kbn-ui-shared-deps.v8.light': ['@elastic/eui/dist/eui_theme_amsterdam_light.css'], }, context: __dirname, devtool: dev ? '#cheap-source-map' : false, diff --git a/rfcs/text/0010_service_status.md b/rfcs/text/0010_service_status.md index ded594930a36..76195c4f1ab8 100644 --- a/rfcs/text/0010_service_status.md +++ b/rfcs/text/0010_service_status.md @@ -137,7 +137,7 @@ interface StatusSetup { * Current status for all dependencies of the current plugin. * Each key of the `Record` is a plugin id. */ - plugins$: Observable>; + dependencies$: Observable>; /** * The status of this plugin as derived from its dependencies. diff --git a/src/legacy/utils/binder.ts b/src/cli/cluster/binder.ts similarity index 100% rename from src/legacy/utils/binder.ts rename to src/cli/cluster/binder.ts diff --git a/src/legacy/utils/binder_for.ts b/src/cli/cluster/binder_for.ts similarity index 100% rename from src/legacy/utils/binder_for.ts rename to src/cli/cluster/binder_for.ts diff --git a/src/cli/cluster/worker.ts b/src/cli/cluster/worker.ts index 097a54918742..c8a8a067d30b 100644 --- a/src/cli/cluster/worker.ts +++ b/src/cli/cluster/worker.ts @@ -21,7 +21,7 @@ import _ from 'lodash'; import cluster from 'cluster'; import { EventEmitter } from 'events'; -import { BinderFor } from '../../legacy/utils/binder_for'; +import { BinderFor } from './binder_for'; import { fromRoot } from '../../core/server/utils'; const cliPath = fromRoot('src/cli'); diff --git a/src/cli_keystore/add.js b/src/cli_keystore/add.js index 462259ec942d..232392f34c63 100644 --- a/src/cli_keystore/add.js +++ b/src/cli_keystore/add.js @@ -18,7 +18,7 @@ */ import { Logger } from '../cli_plugin/lib/logger'; -import { confirm, question } from '../legacy/server/utils'; +import { confirm, question } from './utils'; import { createPromiseFromStreams, createConcatStream } from '../core/server/utils'; /** diff --git a/src/cli_keystore/add.test.js b/src/cli_keystore/add.test.js index b5d5009667eb..f1adee8879bc 100644 --- a/src/cli_keystore/add.test.js +++ b/src/cli_keystore/add.test.js @@ -42,7 +42,7 @@ import { PassThrough } from 'stream'; import { Keystore } from '../legacy/server/keystore'; import { add } from './add'; import { Logger } from '../cli_plugin/lib/logger'; -import * as prompt from '../legacy/server/utils/prompt'; +import * as prompt from './utils/prompt'; describe('Kibana keystore', () => { describe('add', () => { diff --git a/src/cli_keystore/create.js b/src/cli_keystore/create.js index 8be1eb36882f..55fe2c151dec 100644 --- a/src/cli_keystore/create.js +++ b/src/cli_keystore/create.js @@ -18,7 +18,7 @@ */ import { Logger } from '../cli_plugin/lib/logger'; -import { confirm } from '../legacy/server/utils'; +import { confirm } from './utils'; export async function create(keystore, command, options) { const logger = new Logger(options); diff --git a/src/cli_keystore/create.test.js b/src/cli_keystore/create.test.js index f48b3775ddff..cb85475eab1c 100644 --- a/src/cli_keystore/create.test.js +++ b/src/cli_keystore/create.test.js @@ -41,7 +41,7 @@ import sinon from 'sinon'; import { Keystore } from '../legacy/server/keystore'; import { create } from './create'; import { Logger } from '../cli_plugin/lib/logger'; -import * as prompt from '../legacy/server/utils/prompt'; +import * as prompt from './utils/prompt'; describe('Kibana keystore', () => { describe('create', () => { diff --git a/src/legacy/server/utils/index.js b/src/cli_keystore/utils/index.js similarity index 100% rename from src/legacy/server/utils/index.js rename to src/cli_keystore/utils/index.js diff --git a/src/legacy/server/utils/prompt.js b/src/cli_keystore/utils/prompt.js similarity index 100% rename from src/legacy/server/utils/prompt.js rename to src/cli_keystore/utils/prompt.js diff --git a/src/legacy/server/utils/prompt.test.js b/src/cli_keystore/utils/prompt.test.js similarity index 100% rename from src/legacy/server/utils/prompt.test.js rename to src/cli_keystore/utils/prompt.test.js diff --git a/src/core/public/core_app/status/lib/load_status.test.ts b/src/core/public/core_app/status/lib/load_status.test.ts index 3a444a444846..5a9f982e106a 100644 --- a/src/core/public/core_app/status/lib/load_status.test.ts +++ b/src/core/public/core_app/status/lib/load_status.test.ts @@ -57,6 +57,7 @@ const mockedResponse: StatusResponse = { ], }, metrics: { + collected_at: new Date('2020-01-01 01:00:00'), collection_interval_in_millis: 1000, os: { platform: 'darwin' as const, diff --git a/src/core/public/core_app/styles/_globals_v7dark.scss b/src/core/public/core_app/styles/_globals_v7dark.scss index 8ac841aab846..9a4a965d63a3 100644 --- a/src/core/public/core_app/styles/_globals_v7dark.scss +++ b/src/core/public/core_app/styles/_globals_v7dark.scss @@ -3,9 +3,6 @@ // prepended to all .scss imports (from JS, when v7dark theme selected) @import '@elastic/eui/src/themes/eui/eui_colors_dark'; - -@import '@elastic/eui/src/global_styling/functions/index'; -@import '@elastic/eui/src/global_styling/variables/index'; -@import '@elastic/eui/src/global_styling/mixins/index'; +@import '@elastic/eui/src/themes/eui/eui_globals'; @import './mixins'; diff --git a/src/core/public/core_app/styles/_globals_v7light.scss b/src/core/public/core_app/styles/_globals_v7light.scss index 701bbdfe0366..ddb4b5b31fa1 100644 --- a/src/core/public/core_app/styles/_globals_v7light.scss +++ b/src/core/public/core_app/styles/_globals_v7light.scss @@ -3,9 +3,6 @@ // prepended to all .scss imports (from JS, when v7light theme selected) @import '@elastic/eui/src/themes/eui/eui_colors_light'; - -@import '@elastic/eui/src/global_styling/functions/index'; -@import '@elastic/eui/src/global_styling/variables/index'; -@import '@elastic/eui/src/global_styling/mixins/index'; +@import '@elastic/eui/src/themes/eui/eui_globals'; @import './mixins'; diff --git a/src/core/public/core_app/styles/_globals_v8dark.scss b/src/core/public/core_app/styles/_globals_v8dark.scss index 972365e9e9d0..9ad9108f350f 100644 --- a/src/core/public/core_app/styles/_globals_v8dark.scss +++ b/src/core/public/core_app/styles/_globals_v8dark.scss @@ -3,14 +3,6 @@ // prepended to all .scss imports (from JS, when v8dark theme selected) @import '@elastic/eui/src/themes/eui-amsterdam/eui_amsterdam_colors_dark'; - -@import '@elastic/eui/src/global_styling/functions/index'; -@import '@elastic/eui/src/themes/eui-amsterdam/global_styling/functions/index'; - -@import '@elastic/eui/src/global_styling/variables/index'; -@import '@elastic/eui/src/themes/eui-amsterdam/global_styling/variables/index'; - -@import '@elastic/eui/src/global_styling/mixins/index'; -@import '@elastic/eui/src/themes/eui-amsterdam/global_styling/mixins/index'; +@import '@elastic/eui/src/themes/eui-amsterdam/eui_amsterdam_globals'; @import './mixins'; diff --git a/src/core/public/core_app/styles/_globals_v8light.scss b/src/core/public/core_app/styles/_globals_v8light.scss index dc99f4d45082..a6b2cb84c206 100644 --- a/src/core/public/core_app/styles/_globals_v8light.scss +++ b/src/core/public/core_app/styles/_globals_v8light.scss @@ -3,14 +3,6 @@ // prepended to all .scss imports (from JS, when v8light theme selected) @import '@elastic/eui/src/themes/eui-amsterdam/eui_amsterdam_colors_light'; - -@import '@elastic/eui/src/global_styling/functions/index'; -@import '@elastic/eui/src/themes/eui-amsterdam/global_styling/functions/index'; - -@import '@elastic/eui/src/global_styling/variables/index'; -@import '@elastic/eui/src/themes/eui-amsterdam/global_styling/variables/index'; - -@import '@elastic/eui/src/global_styling/mixins/index'; -@import '@elastic/eui/src/themes/eui-amsterdam/global_styling/mixins/index'; +@import '@elastic/eui/src/themes/eui-amsterdam/eui_amsterdam_globals'; @import './mixins'; diff --git a/src/core/public/doc_links/doc_links_service.ts b/src/core/public/doc_links/doc_links_service.ts index fc753517fd94..95ac8bba5704 100644 --- a/src/core/public/doc_links/doc_links_service.ts +++ b/src/core/public/doc_links/doc_links_service.ts @@ -129,7 +129,7 @@ export class DocLinksService { }, visualize: { guide: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/visualize.html`, - timelionDeprecation: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/timelion.html#timelion-deprecation`, + timelionDeprecation: `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/dashboard.html#timelion-deprecation`, }, }, }); diff --git a/src/core/public/styles/_base.scss b/src/core/public/styles/_base.scss index 9b06b526fc7d..427c6b773543 100644 --- a/src/core/public/styles/_base.scss +++ b/src/core/public/styles/_base.scss @@ -1,4 +1,10 @@ +// Charts themes available app-wide +@import '@elastic/charts/dist/theme'; +@import '@elastic/eui/src/themes/charts/theme'; + +// Grab some nav-specific EUI vars @import '@elastic/eui/src/components/collapsible_nav/variables'; + // Application Layout // chrome-context diff --git a/src/core/server/config/deprecation/core_deprecations.ts b/src/core/server/config/deprecation/core_deprecations.ts index e4e881ab2437..2b8b8e383da2 100644 --- a/src/core/server/config/deprecation/core_deprecations.ts +++ b/src/core/server/config/deprecation/core_deprecations.ts @@ -113,7 +113,7 @@ const mapManifestServiceUrlDeprecation: ConfigDeprecation = (settings, fromPath, return settings; }; -export const coreDeprecationProvider: ConfigDeprecationProvider = ({ unusedFromRoot }) => [ +export const coreDeprecationProvider: ConfigDeprecationProvider = ({ rename, unusedFromRoot }) => [ unusedFromRoot('savedObjects.indexCheckTimeout'), unusedFromRoot('server.xsrf.token'), unusedFromRoot('maps.manifestServiceUrl'), @@ -136,6 +136,8 @@ export const coreDeprecationProvider: ConfigDeprecationProvider = ({ unusedFromR unusedFromRoot('optimize.workers'), unusedFromRoot('optimize.profile'), unusedFromRoot('optimize.validateSyntaxOfNodeModules'), + rename('cpu.cgroup.path.override', 'ops.cGroupOverrides.cpuPath'), + rename('cpuacct.cgroup.path.override', 'ops.cGroupOverrides.cpuAcctPath'), configPathDeprecation, dataPathDeprecation, rewriteBasePathDeprecation, diff --git a/src/core/server/index.ts b/src/core/server/index.ts index c17d3d754677..97aca74bfd48 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -266,9 +266,7 @@ export { SavedObjectUnsanitizedDoc, SavedObjectsRepositoryFactory, SavedObjectsResolveImportErrorsOptions, - SavedObjectsSchema, SavedObjectsSerializer, - SavedObjectsLegacyService, SavedObjectsUpdateOptions, SavedObjectsUpdateResponse, SavedObjectsAddToNamespacesOptions, diff --git a/src/core/server/legacy/legacy_service.mock.ts b/src/core/server/legacy/legacy_service.mock.ts index 26ec52185a5d..c27f5be04d96 100644 --- a/src/core/server/legacy/legacy_service.mock.ts +++ b/src/core/server/legacy/legacy_service.mock.ts @@ -24,13 +24,7 @@ type LegacyServiceMock = jest.Mocked & { legacyId const createDiscoverPluginsMock = (): LegacyServiceDiscoverPlugins => ({ pluginSpecs: [], - uiExports: { - savedObjectSchemas: {}, - savedObjectMappings: [], - savedObjectMigrations: {}, - savedObjectValidations: {}, - savedObjectsManagement: {}, - }, + uiExports: {}, navLinks: [], pluginExtendedConfig: { get: jest.fn(), diff --git a/src/core/server/legacy/legacy_service.ts b/src/core/server/legacy/legacy_service.ts index 880011d2e192..6e6d5cfc2434 100644 --- a/src/core/server/legacy/legacy_service.ts +++ b/src/core/server/legacy/legacy_service.ts @@ -264,6 +264,7 @@ export class LegacyService implements CoreService { getTypeRegistry: startDeps.core.savedObjects.getTypeRegistry, }, metrics: { + collectionInterval: startDeps.core.metrics.collectionInterval, getOpsMetrics$: startDeps.core.metrics.getOpsMetrics$, }, uiSettings: { asScopedToClient: startDeps.core.uiSettings.asScopedToClient }, @@ -310,6 +311,17 @@ export class LegacyService implements CoreService { status: { core$: setupDeps.core.status.core$, overall$: setupDeps.core.status.overall$, + set: () => { + throw new Error(`core.status.set is unsupported in legacy`); + }, + // @ts-expect-error + get dependencies$() { + throw new Error(`core.status.dependencies$ is unsupported in legacy`); + }, + // @ts-expect-error + get derivedStatus$() { + throw new Error(`core.status.derivedStatus$ is unsupported in legacy`); + }, }, uiSettings: { register: setupDeps.core.uiSettings.register, @@ -341,11 +353,9 @@ export class LegacyService implements CoreService { registerStaticDir: setupDeps.core.http.registerStaticDir, }, hapiServer: setupDeps.core.http.server, - kibanaMigrator: startDeps.core.savedObjects.migrator, uiPlugins: setupDeps.uiPlugins, elasticsearch: setupDeps.core.elasticsearch, rendering: setupDeps.core.rendering, - savedObjectsClientProvider: startDeps.core.savedObjects.clientProvider, legacy: this.legacyInternals, }, logger: this.coreContext.logger, diff --git a/src/core/server/legacy/types.ts b/src/core/server/legacy/types.ts index cf08689a6d0d..1105308fd44c 100644 --- a/src/core/server/legacy/types.ts +++ b/src/core/server/legacy/types.ts @@ -24,7 +24,6 @@ import { KibanaRequest, LegacyRequest } from '../http'; import { InternalCoreSetup, InternalCoreStart } from '../internal_types'; import { PluginsServiceSetup, PluginsServiceStart, UiPlugins } from '../plugins'; import { InternalRenderingServiceSetup } from '../rendering'; -import { SavedObjectsLegacyUiExports } from '../types'; /** * @internal @@ -128,13 +127,13 @@ export type LegacyNavLink = Omit; unknown?: [{ pluginSpec: LegacyPluginSpec; type: unknown }]; -}; +} /** * @public diff --git a/src/core/server/metrics/collectors/cgroup.test.ts b/src/core/server/metrics/collectors/cgroup.test.ts new file mode 100644 index 000000000000..39f917b9f0ba --- /dev/null +++ b/src/core/server/metrics/collectors/cgroup.test.ts @@ -0,0 +1,115 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import mockFs from 'mock-fs'; +import { OsCgroupMetricsCollector } from './cgroup'; + +describe('OsCgroupMetricsCollector', () => { + afterEach(() => mockFs.restore()); + + it('returns empty object when no cgroup file present', async () => { + mockFs({ + '/proc/self': { + /** empty directory */ + }, + }); + + const collector = new OsCgroupMetricsCollector({}); + expect(await collector.collect()).toEqual({}); + }); + + it('collects default cgroup data', async () => { + mockFs({ + '/proc/self/cgroup': ` +123:memory:/groupname +123:cpu:/groupname +123:cpuacct:/groupname + `, + '/sys/fs/cgroup/cpuacct/groupname/cpuacct.usage': '111', + '/sys/fs/cgroup/cpu/groupname/cpu.cfs_period_us': '222', + '/sys/fs/cgroup/cpu/groupname/cpu.cfs_quota_us': '333', + '/sys/fs/cgroup/cpu/groupname/cpu.stat': ` +nr_periods 444 +nr_throttled 555 +throttled_time 666 + `, + }); + + const collector = new OsCgroupMetricsCollector({}); + expect(await collector.collect()).toMatchInlineSnapshot(` + Object { + "cpu": Object { + "cfs_period_micros": 222, + "cfs_quota_micros": 333, + "control_group": "/groupname", + "stat": Object { + "number_of_elapsed_periods": 444, + "number_of_times_throttled": 555, + "time_throttled_nanos": 666, + }, + }, + "cpuacct": Object { + "control_group": "/groupname", + "usage_nanos": 111, + }, + } + `); + }); + + it('collects override cgroup data', async () => { + mockFs({ + '/proc/self/cgroup': ` +123:memory:/groupname +123:cpu:/groupname +123:cpuacct:/groupname + `, + '/sys/fs/cgroup/cpuacct/xxcustomcpuacctxx/cpuacct.usage': '111', + '/sys/fs/cgroup/cpu/xxcustomcpuxx/cpu.cfs_period_us': '222', + '/sys/fs/cgroup/cpu/xxcustomcpuxx/cpu.cfs_quota_us': '333', + '/sys/fs/cgroup/cpu/xxcustomcpuxx/cpu.stat': ` +nr_periods 444 +nr_throttled 555 +throttled_time 666 + `, + }); + + const collector = new OsCgroupMetricsCollector({ + cpuAcctPath: 'xxcustomcpuacctxx', + cpuPath: 'xxcustomcpuxx', + }); + expect(await collector.collect()).toMatchInlineSnapshot(` + Object { + "cpu": Object { + "cfs_period_micros": 222, + "cfs_quota_micros": 333, + "control_group": "xxcustomcpuxx", + "stat": Object { + "number_of_elapsed_periods": 444, + "number_of_times_throttled": 555, + "time_throttled_nanos": 666, + }, + }, + "cpuacct": Object { + "control_group": "xxcustomcpuacctxx", + "usage_nanos": 111, + }, + } + `); + }); +}); diff --git a/src/core/server/metrics/collectors/cgroup.ts b/src/core/server/metrics/collectors/cgroup.ts new file mode 100644 index 000000000000..867ea44dff1a --- /dev/null +++ b/src/core/server/metrics/collectors/cgroup.ts @@ -0,0 +1,194 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import fs from 'fs'; +import { join as joinPath } from 'path'; +import { MetricsCollector, OpsOsMetrics } from './types'; + +type OsCgroupMetrics = Pick; + +interface OsCgroupMetricsCollectorOptions { + cpuPath?: string; + cpuAcctPath?: string; +} + +export class OsCgroupMetricsCollector implements MetricsCollector { + /** Used to prevent unnecessary file reads on systems not using cgroups. */ + private noCgroupPresent = false; + private cpuPath?: string; + private cpuAcctPath?: string; + + constructor(private readonly options: OsCgroupMetricsCollectorOptions) {} + + public async collect(): Promise { + try { + await this.initializePaths(); + if (this.noCgroupPresent || !this.cpuAcctPath || !this.cpuPath) { + return {}; + } + + const [cpuAcctUsage, cpuFsPeriod, cpuFsQuota, cpuStat] = await Promise.all([ + readCPUAcctUsage(this.cpuAcctPath), + readCPUFsPeriod(this.cpuPath), + readCPUFsQuota(this.cpuPath), + readCPUStat(this.cpuPath), + ]); + + return { + cpuacct: { + control_group: this.cpuAcctPath, + usage_nanos: cpuAcctUsage, + }, + + cpu: { + control_group: this.cpuPath, + cfs_period_micros: cpuFsPeriod, + cfs_quota_micros: cpuFsQuota, + stat: cpuStat, + }, + }; + } catch (err) { + if (err.code === 'ENOENT') { + this.noCgroupPresent = true; + return {}; + } else { + throw err; + } + } + } + + public reset() {} + + private async initializePaths() { + // Perform this setup lazily on the first collect call and then memoize the results. + // Makes the assumption this data doesn't change while the process is running. + if (this.cpuPath && this.cpuAcctPath) { + return; + } + + // Only read the file if both options are undefined. + if (!this.options.cpuPath || !this.options.cpuAcctPath) { + const cgroups = await readControlGroups(); + this.cpuPath = this.options.cpuPath || cgroups[GROUP_CPU]; + this.cpuAcctPath = this.options.cpuAcctPath || cgroups[GROUP_CPUACCT]; + } else { + this.cpuPath = this.options.cpuPath; + this.cpuAcctPath = this.options.cpuAcctPath; + } + + // prevents undefined cgroup paths + if (!this.cpuPath || !this.cpuAcctPath) { + this.noCgroupPresent = true; + } + } +} + +const CONTROL_GROUP_RE = new RegExp('\\d+:([^:]+):(/.*)'); +const CONTROLLER_SEPARATOR_RE = ','; + +const PROC_SELF_CGROUP_FILE = '/proc/self/cgroup'; +const PROC_CGROUP_CPU_DIR = '/sys/fs/cgroup/cpu'; +const PROC_CGROUP_CPUACCT_DIR = '/sys/fs/cgroup/cpuacct'; + +const GROUP_CPUACCT = 'cpuacct'; +const CPUACCT_USAGE_FILE = 'cpuacct.usage'; + +const GROUP_CPU = 'cpu'; +const CPU_FS_PERIOD_US_FILE = 'cpu.cfs_period_us'; +const CPU_FS_QUOTA_US_FILE = 'cpu.cfs_quota_us'; +const CPU_STATS_FILE = 'cpu.stat'; + +async function readControlGroups() { + const data = await fs.promises.readFile(PROC_SELF_CGROUP_FILE); + + return data + .toString() + .split(/\n/) + .reduce((acc, line) => { + const matches = line.match(CONTROL_GROUP_RE); + + if (matches !== null) { + const controllers = matches[1].split(CONTROLLER_SEPARATOR_RE); + controllers.forEach((controller) => { + acc[controller] = matches[2]; + }); + } + + return acc; + }, {} as Record); +} + +async function fileContentsToInteger(path: string) { + const data = await fs.promises.readFile(path); + return parseInt(data.toString(), 10); +} + +function readCPUAcctUsage(controlGroup: string) { + return fileContentsToInteger(joinPath(PROC_CGROUP_CPUACCT_DIR, controlGroup, CPUACCT_USAGE_FILE)); +} + +function readCPUFsPeriod(controlGroup: string) { + return fileContentsToInteger(joinPath(PROC_CGROUP_CPU_DIR, controlGroup, CPU_FS_PERIOD_US_FILE)); +} + +function readCPUFsQuota(controlGroup: string) { + return fileContentsToInteger(joinPath(PROC_CGROUP_CPU_DIR, controlGroup, CPU_FS_QUOTA_US_FILE)); +} + +async function readCPUStat(controlGroup: string) { + const stat = { + number_of_elapsed_periods: -1, + number_of_times_throttled: -1, + time_throttled_nanos: -1, + }; + + try { + const data = await fs.promises.readFile( + joinPath(PROC_CGROUP_CPU_DIR, controlGroup, CPU_STATS_FILE) + ); + return data + .toString() + .split(/\n/) + .reduce((acc, line) => { + const fields = line.split(/\s+/); + + switch (fields[0]) { + case 'nr_periods': + acc.number_of_elapsed_periods = parseInt(fields[1], 10); + break; + + case 'nr_throttled': + acc.number_of_times_throttled = parseInt(fields[1], 10); + break; + + case 'throttled_time': + acc.time_throttled_nanos = parseInt(fields[1], 10); + break; + } + + return acc; + }, stat); + } catch (err) { + if (err.code === 'ENOENT') { + return stat; + } + + throw err; + } +} diff --git a/src/core/server/metrics/collectors/collector.mock.ts b/src/core/server/metrics/collectors/collector.mock.ts new file mode 100644 index 000000000000..2a942e1fafe6 --- /dev/null +++ b/src/core/server/metrics/collectors/collector.mock.ts @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { MetricsCollector } from './types'; + +const createCollector = (collectReturnValue: any = {}): jest.Mocked> => { + const collector: jest.Mocked> = { + collect: jest.fn().mockResolvedValue(collectReturnValue), + reset: jest.fn(), + }; + + return collector; +}; + +export const metricsCollectorMock = { + create: createCollector, +}; diff --git a/src/core/server/metrics/collectors/index.ts b/src/core/server/metrics/collectors/index.ts index f58ab02e6388..4540cb79be74 100644 --- a/src/core/server/metrics/collectors/index.ts +++ b/src/core/server/metrics/collectors/index.ts @@ -18,6 +18,6 @@ */ export { OpsProcessMetrics, OpsOsMetrics, OpsServerMetrics, MetricsCollector } from './types'; -export { OsMetricsCollector } from './os'; +export { OsMetricsCollector, OpsMetricsCollectorOptions } from './os'; export { ProcessMetricsCollector } from './process'; export { ServerMetricsCollector } from './server'; diff --git a/src/core/server/saved_objects/schema/index.ts b/src/core/server/metrics/collectors/os.test.mocks.ts similarity index 77% rename from src/core/server/saved_objects/schema/index.ts rename to src/core/server/metrics/collectors/os.test.mocks.ts index d30bbb8d34cd..ee02b8c80215 100644 --- a/src/core/server/saved_objects/schema/index.ts +++ b/src/core/server/metrics/collectors/os.test.mocks.ts @@ -17,4 +17,9 @@ * under the License. */ -export { SavedObjectsSchema, SavedObjectsSchemaDefinition } from './schema'; +import { metricsCollectorMock } from './collector.mock'; + +export const cgroupCollectorMock = metricsCollectorMock.create(); +jest.doMock('./cgroup', () => ({ + OsCgroupMetricsCollector: jest.fn(() => cgroupCollectorMock), +})); diff --git a/src/core/server/metrics/collectors/os.test.ts b/src/core/server/metrics/collectors/os.test.ts index 7d5a6da90b7d..5e52cecb76be 100644 --- a/src/core/server/metrics/collectors/os.test.ts +++ b/src/core/server/metrics/collectors/os.test.ts @@ -20,6 +20,7 @@ jest.mock('getos', () => (cb: Function) => cb(null, { dist: 'distrib', release: 'release' })); import os from 'os'; +import { cgroupCollectorMock } from './os.test.mocks'; import { OsMetricsCollector } from './os'; describe('OsMetricsCollector', () => { @@ -27,6 +28,8 @@ describe('OsMetricsCollector', () => { beforeEach(() => { collector = new OsMetricsCollector(); + cgroupCollectorMock.collect.mockReset(); + cgroupCollectorMock.reset.mockReset(); }); afterEach(() => { @@ -96,4 +99,9 @@ describe('OsMetricsCollector', () => { '15m': fifteenMinLoad, }); }); + + it('calls the cgroup sub-collector', async () => { + await collector.collect(); + expect(cgroupCollectorMock.collect).toHaveBeenCalled(); + }); }); diff --git a/src/core/server/metrics/collectors/os.ts b/src/core/server/metrics/collectors/os.ts index 59bef9d8ddd2..eae49278405a 100644 --- a/src/core/server/metrics/collectors/os.ts +++ b/src/core/server/metrics/collectors/os.ts @@ -21,10 +21,22 @@ import os from 'os'; import getosAsync, { LinuxOs } from 'getos'; import { promisify } from 'util'; import { OpsOsMetrics, MetricsCollector } from './types'; +import { OsCgroupMetricsCollector } from './cgroup'; const getos = promisify(getosAsync); +export interface OpsMetricsCollectorOptions { + cpuPath?: string; + cpuAcctPath?: string; +} + export class OsMetricsCollector implements MetricsCollector { + private readonly cgroupCollector: OsCgroupMetricsCollector; + + constructor(options: OpsMetricsCollectorOptions = {}) { + this.cgroupCollector = new OsCgroupMetricsCollector(options); + } + public async collect(): Promise { const platform = os.platform(); const load = os.loadavg(); @@ -43,20 +55,30 @@ export class OsMetricsCollector implements MetricsCollector { used_in_bytes: os.totalmem() - os.freemem(), }, uptime_in_millis: os.uptime() * 1000, + ...(await this.getDistroStats(platform)), + ...(await this.cgroupCollector.collect()), }; + return metrics; + } + + public reset() {} + + private async getDistroStats( + platform: string + ): Promise> { if (platform === 'linux') { try { const distro = (await getos()) as LinuxOs; - metrics.distro = distro.dist; - metrics.distroRelease = `${distro.dist}-${distro.release}`; + return { + distro: distro.dist, + distroRelease: `${distro.dist}-${distro.release}`, + }; } catch (e) { // ignore errors } } - return metrics; + return {}; } - - public reset() {} } diff --git a/src/core/server/metrics/collectors/types.ts b/src/core/server/metrics/collectors/types.ts index 73e8975a6b36..77ea13a1f078 100644 --- a/src/core/server/metrics/collectors/types.ts +++ b/src/core/server/metrics/collectors/types.ts @@ -85,6 +85,33 @@ export interface OpsOsMetrics { }; /** the OS uptime */ uptime_in_millis: number; + + /** cpu accounting metrics, undefined when not running in a cgroup */ + cpuacct?: { + /** name of this process's cgroup */ + control_group: string; + /** cpu time used by this process's cgroup */ + usage_nanos: number; + }; + + /** cpu cgroup metrics, undefined when not running in a cgroup */ + cpu?: { + /** name of this process's cgroup */ + control_group: string; + /** the length of the cfs period */ + cfs_period_micros: number; + /** total available run-time within a cfs period */ + cfs_quota_micros: number; + /** current stats on the cfs periods */ + stat: { + /** number of cfs periods that elapsed */ + number_of_elapsed_periods: number; + /** number of times the cgroup has been throttled */ + number_of_times_throttled: number; + /** total amount of time the cgroup has been throttled for */ + time_throttled_nanos: number; + }; + }; } /** diff --git a/src/core/server/metrics/metrics_service.mock.ts b/src/core/server/metrics/metrics_service.mock.ts index 769f6ee2a549..2af653004a47 100644 --- a/src/core/server/metrics/metrics_service.mock.ts +++ b/src/core/server/metrics/metrics_service.mock.ts @@ -21,20 +21,18 @@ import { MetricsService } from './metrics_service'; import { InternalMetricsServiceSetup, InternalMetricsServiceStart, + MetricsServiceSetup, MetricsServiceStart, } from './types'; const createInternalSetupContractMock = () => { - const setupContract: jest.Mocked = {}; - return setupContract; -}; - -const createStartContractMock = () => { - const startContract: jest.Mocked = { + const setupContract: jest.Mocked = { + collectionInterval: 30000, getOpsMetrics$: jest.fn(), }; - startContract.getOpsMetrics$.mockReturnValue( + setupContract.getOpsMetrics$.mockReturnValue( new BehaviorSubject({ + collected_at: new Date('2020-01-01 01:00:00'), process: { memory: { heap: { total_in_bytes: 1, used_in_bytes: 1, size_limit: 1 }, @@ -56,11 +54,21 @@ const createStartContractMock = () => { concurrent_connections: 1, }) ); + return setupContract; +}; + +const createSetupContractMock = () => { + const startContract: jest.Mocked = createInternalSetupContractMock(); return startContract; }; const createInternalStartContractMock = () => { - const startContract: jest.Mocked = createStartContractMock(); + const startContract: jest.Mocked = createInternalSetupContractMock(); + return startContract; +}; + +const createStartContractMock = () => { + const startContract: jest.Mocked = createInternalSetupContractMock(); return startContract; }; @@ -77,7 +85,7 @@ const createMock = () => { export const metricsServiceMock = { create: createMock, - createSetupContract: createStartContractMock, + createSetupContract: createSetupContractMock, createStartContract: createStartContractMock, createInternalSetupContract: createInternalSetupContractMock, createInternalStartContract: createInternalStartContractMock, diff --git a/src/core/server/metrics/metrics_service.ts b/src/core/server/metrics/metrics_service.ts index f28fb21aaac0..d4696b3aa9aa 100644 --- a/src/core/server/metrics/metrics_service.ts +++ b/src/core/server/metrics/metrics_service.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Subject } from 'rxjs'; +import { ReplaySubject } from 'rxjs'; import { first } from 'rxjs/operators'; import { CoreService } from '../../types'; import { CoreContext } from '../core_context'; @@ -37,26 +37,21 @@ export class MetricsService private readonly logger: Logger; private metricsCollector?: OpsMetricsCollector; private collectInterval?: NodeJS.Timeout; - private metrics$ = new Subject(); + private metrics$ = new ReplaySubject(); + private service?: InternalMetricsServiceSetup; constructor(private readonly coreContext: CoreContext) { this.logger = coreContext.logger.get('metrics'); } public async setup({ http }: MetricsServiceSetupDeps): Promise { - this.metricsCollector = new OpsMetricsCollector(http.server); - return {}; - } - - public async start(): Promise { - if (!this.metricsCollector) { - throw new Error('#setup() needs to be run first'); - } const config = await this.coreContext.configService .atPath(opsConfig.path) .pipe(first()) .toPromise(); + this.metricsCollector = new OpsMetricsCollector(http.server, config.cGroupOverrides); + await this.refreshMetrics(); this.collectInterval = setInterval(() => { @@ -65,9 +60,20 @@ export class MetricsService const metricsObservable = this.metrics$.asObservable(); - return { + this.service = { + collectionInterval: config.interval.asMilliseconds(), getOpsMetrics$: () => metricsObservable, }; + + return this.service; + } + + public async start(): Promise { + if (!this.service) { + throw new Error('#setup() needs to be run first'); + } + + return this.service; } private async refreshMetrics() { diff --git a/src/core/server/metrics/ops_config.ts b/src/core/server/metrics/ops_config.ts index bd6ae5cc5474..5f3f67e931c3 100644 --- a/src/core/server/metrics/ops_config.ts +++ b/src/core/server/metrics/ops_config.ts @@ -23,6 +23,10 @@ export const opsConfig = { path: 'ops', schema: schema.object({ interval: schema.duration({ defaultValue: '5s' }), + cGroupOverrides: schema.object({ + cpuPath: schema.maybe(schema.string()), + cpuAcctPath: schema.maybe(schema.string()), + }), }), }; diff --git a/src/core/server/metrics/ops_metrics_collector.test.ts b/src/core/server/metrics/ops_metrics_collector.test.ts index 9e76895b1457..7aa3f7cd3baf 100644 --- a/src/core/server/metrics/ops_metrics_collector.test.ts +++ b/src/core/server/metrics/ops_metrics_collector.test.ts @@ -30,7 +30,7 @@ describe('OpsMetricsCollector', () => { beforeEach(() => { const hapiServer = httpServiceMock.createInternalSetupContract().server; - collector = new OpsMetricsCollector(hapiServer); + collector = new OpsMetricsCollector(hapiServer, {}); mockOsCollector.collect.mockResolvedValue('osMetrics'); }); @@ -51,6 +51,7 @@ describe('OpsMetricsCollector', () => { expect(mockServerCollector.collect).toHaveBeenCalledTimes(1); expect(metrics).toEqual({ + collected_at: expect.any(Date), process: 'processMetrics', os: 'osMetrics', requests: 'serverRequestsMetrics', diff --git a/src/core/server/metrics/ops_metrics_collector.ts b/src/core/server/metrics/ops_metrics_collector.ts index 525515dba145..af74caa6cb38 100644 --- a/src/core/server/metrics/ops_metrics_collector.ts +++ b/src/core/server/metrics/ops_metrics_collector.ts @@ -21,6 +21,7 @@ import { Server as HapiServer } from 'hapi'; import { ProcessMetricsCollector, OsMetricsCollector, + OpsMetricsCollectorOptions, ServerMetricsCollector, MetricsCollector, } from './collectors'; @@ -31,9 +32,9 @@ export class OpsMetricsCollector implements MetricsCollector { private readonly osCollector: OsMetricsCollector; private readonly serverCollector: ServerMetricsCollector; - constructor(server: HapiServer) { + constructor(server: HapiServer, opsOptions: OpsMetricsCollectorOptions) { this.processCollector = new ProcessMetricsCollector(); - this.osCollector = new OsMetricsCollector(); + this.osCollector = new OsMetricsCollector(opsOptions); this.serverCollector = new ServerMetricsCollector(server); } @@ -44,6 +45,7 @@ export class OpsMetricsCollector implements MetricsCollector { this.serverCollector.collect(), ]); return { + collected_at: new Date(), process, os, ...server, diff --git a/src/core/server/metrics/types.ts b/src/core/server/metrics/types.ts index cbf0acacd6ba..c177b3ed2511 100644 --- a/src/core/server/metrics/types.ts +++ b/src/core/server/metrics/types.ts @@ -20,14 +20,15 @@ import { Observable } from 'rxjs'; import { OpsProcessMetrics, OpsOsMetrics, OpsServerMetrics } from './collectors'; -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface MetricsServiceSetup {} /** * APIs to retrieves metrics gathered and exposed by the core platform. * * @public */ -export interface MetricsServiceStart { +export interface MetricsServiceSetup { + /** Interval metrics are collected in milliseconds */ + readonly collectionInterval: number; + /** * Retrieve an observable emitting the {@link OpsMetrics} gathered. * The observable will emit an initial value during core's `start` phase, and a new value every fixed interval of time, @@ -42,6 +43,12 @@ export interface MetricsServiceStart { */ getOpsMetrics$: () => Observable; } +/** + * {@inheritdoc MetricsServiceSetup} + * + * @public + */ +export type MetricsServiceStart = MetricsServiceSetup; export type InternalMetricsServiceSetup = MetricsServiceSetup; export type InternalMetricsServiceStart = MetricsServiceStart; @@ -53,6 +60,8 @@ export type InternalMetricsServiceStart = MetricsServiceStart; * @public */ export interface OpsMetrics { + /** Time metrics were recorded at. */ + collected_at: Date; /** Process related metrics */ process: OpsProcessMetrics; /** OS related metrics */ diff --git a/src/core/server/plugins/plugin_context.ts b/src/core/server/plugins/plugin_context.ts index fa2659ca130a..af0b0e19b322 100644 --- a/src/core/server/plugins/plugin_context.ts +++ b/src/core/server/plugins/plugin_context.ts @@ -185,6 +185,9 @@ export function createPluginSetupContext( status: { core$: deps.status.core$, overall$: deps.status.overall$, + set: deps.status.plugins.set.bind(null, plugin.name), + dependencies$: deps.status.plugins.getDependenciesStatus$(plugin.name), + derivedStatus$: deps.status.plugins.getDerivedStatus$(plugin.name), }, uiSettings: { register: deps.uiSettings.register, @@ -233,6 +236,7 @@ export function createPluginStartContext( getTypeRegistry: deps.savedObjects.getTypeRegistry, }, metrics: { + collectionInterval: deps.metrics.collectionInterval, getOpsMetrics$: deps.metrics.getOpsMetrics$, }, uiSettings: { diff --git a/src/core/server/plugins/plugins_system.test.ts b/src/core/server/plugins/plugins_system.test.ts index 7af77491df1a..71ac31db13f9 100644 --- a/src/core/server/plugins/plugins_system.test.ts +++ b/src/core/server/plugins/plugins_system.test.ts @@ -100,15 +100,27 @@ test('getPluginDependencies returns dependency tree of symbols', () => { pluginsSystem.addPlugin(createPlugin('no-dep')); expect(pluginsSystem.getPluginDependencies()).toMatchInlineSnapshot(` - Map { - Symbol(plugin-a) => Array [ - Symbol(no-dep), - ], - Symbol(plugin-b) => Array [ - Symbol(plugin-a), - Symbol(no-dep), - ], - Symbol(no-dep) => Array [], + Object { + "asNames": Map { + "plugin-a" => Array [ + "no-dep", + ], + "plugin-b" => Array [ + "plugin-a", + "no-dep", + ], + "no-dep" => Array [], + }, + "asOpaqueIds": Map { + Symbol(plugin-a) => Array [ + Symbol(no-dep), + ], + Symbol(plugin-b) => Array [ + Symbol(plugin-a), + Symbol(no-dep), + ], + Symbol(no-dep) => Array [], + }, } `); }); diff --git a/src/core/server/plugins/plugins_system.ts b/src/core/server/plugins/plugins_system.ts index f5c1b35d678a..b2acd9a6fd04 100644 --- a/src/core/server/plugins/plugins_system.ts +++ b/src/core/server/plugins/plugins_system.ts @@ -20,10 +20,11 @@ import { CoreContext } from '../core_context'; import { Logger } from '../logging'; import { PluginWrapper } from './plugin'; -import { DiscoveredPlugin, PluginName, PluginOpaqueId } from './types'; +import { DiscoveredPlugin, PluginName } from './types'; import { createPluginSetupContext, createPluginStartContext } from './plugin_context'; import { PluginsServiceSetupDeps, PluginsServiceStartDeps } from './plugins_service'; import { withTimeout } from '../../utils'; +import { PluginDependencies } from '.'; const Sec = 1000; /** @internal */ @@ -45,9 +46,19 @@ export class PluginsSystem { * @returns a ReadonlyMap of each plugin and an Array of its available dependencies * @internal */ - public getPluginDependencies(): ReadonlyMap { - // Return dependency map of opaque ids - return new Map( + public getPluginDependencies(): PluginDependencies { + const asNames = new Map( + [...this.plugins].map(([name, plugin]) => [ + plugin.name, + [ + ...new Set([ + ...plugin.requiredPlugins, + ...plugin.optionalPlugins.filter((optPlugin) => this.plugins.has(optPlugin)), + ]), + ].map((depId) => this.plugins.get(depId)!.name), + ]) + ); + const asOpaqueIds = new Map( [...this.plugins].map(([name, plugin]) => [ plugin.opaqueId, [ @@ -58,6 +69,8 @@ export class PluginsSystem { ].map((depId) => this.plugins.get(depId)!.opaqueId), ]) ); + + return { asNames, asOpaqueIds }; } public async setupPlugins(deps: PluginsServiceSetupDeps) { diff --git a/src/core/server/plugins/types.ts b/src/core/server/plugins/types.ts index eb2a9ca3daf5..517261b5bc9b 100644 --- a/src/core/server/plugins/types.ts +++ b/src/core/server/plugins/types.ts @@ -93,6 +93,12 @@ export type PluginName = string; /** @public */ export type PluginOpaqueId = symbol; +/** @internal */ +export interface PluginDependencies { + asNames: ReadonlyMap; + asOpaqueIds: ReadonlyMap; +} + /** * Describes the set of required and optional properties plugin can define in its * mandatory JSON manifest file. diff --git a/src/core/server/saved_objects/__snapshots__/utils.test.ts.snap b/src/core/server/saved_objects/__snapshots__/utils.test.ts.snap deleted file mode 100644 index 7cd0297e5785..000000000000 --- a/src/core/server/saved_objects/__snapshots__/utils.test.ts.snap +++ /dev/null @@ -1,184 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`convertLegacyTypes converts the legacy mappings using default values if no schemas are specified 1`] = ` -Array [ - Object { - "convertToAliasScript": undefined, - "hidden": false, - "indexPattern": undefined, - "management": undefined, - "mappings": Object { - "properties": Object { - "fieldA": Object { - "type": "text", - }, - }, - }, - "migrations": Object {}, - "name": "typeA", - "namespaceType": "single", - }, - Object { - "convertToAliasScript": undefined, - "hidden": false, - "indexPattern": undefined, - "management": undefined, - "mappings": Object { - "properties": Object { - "fieldB": Object { - "type": "text", - }, - }, - }, - "migrations": Object {}, - "name": "typeB", - "namespaceType": "single", - }, - Object { - "convertToAliasScript": undefined, - "hidden": false, - "indexPattern": undefined, - "management": undefined, - "mappings": Object { - "properties": Object { - "fieldC": Object { - "type": "text", - }, - }, - }, - "migrations": Object {}, - "name": "typeC", - "namespaceType": "single", - }, -] -`; - -exports[`convertLegacyTypes merges everything when all are present 1`] = ` -Array [ - Object { - "convertToAliasScript": undefined, - "hidden": true, - "indexPattern": "myIndex", - "management": undefined, - "mappings": Object { - "properties": Object { - "fieldA": Object { - "type": "text", - }, - }, - }, - "migrations": Object { - "1.0.0": [Function], - "2.0.4": [Function], - }, - "name": "typeA", - "namespaceType": "agnostic", - }, - Object { - "convertToAliasScript": "some alias script", - "hidden": false, - "indexPattern": undefined, - "management": undefined, - "mappings": Object { - "properties": Object { - "anotherFieldB": Object { - "type": "boolean", - }, - "fieldB": Object { - "type": "text", - }, - }, - }, - "migrations": Object {}, - "name": "typeB", - "namespaceType": "single", - }, - Object { - "convertToAliasScript": undefined, - "hidden": false, - "indexPattern": undefined, - "management": undefined, - "mappings": Object { - "properties": Object { - "fieldC": Object { - "type": "text", - }, - }, - }, - "migrations": Object { - "1.5.3": [Function], - }, - "name": "typeC", - "namespaceType": "single", - }, -] -`; - -exports[`convertLegacyTypes merges the mappings and the schema to create the type when schema exists for the type 1`] = ` -Array [ - Object { - "convertToAliasScript": undefined, - "hidden": true, - "indexPattern": "fooBar", - "management": undefined, - "mappings": Object { - "properties": Object { - "fieldA": Object { - "type": "text", - }, - }, - }, - "migrations": Object {}, - "name": "typeA", - "namespaceType": "agnostic", - }, - Object { - "convertToAliasScript": undefined, - "hidden": false, - "indexPattern": "barBaz", - "management": undefined, - "mappings": Object { - "properties": Object { - "fieldB": Object { - "type": "text", - }, - }, - }, - "migrations": Object {}, - "name": "typeB", - "namespaceType": "multiple", - }, - Object { - "convertToAliasScript": undefined, - "hidden": false, - "indexPattern": undefined, - "management": undefined, - "mappings": Object { - "properties": Object { - "fieldC": Object { - "type": "text", - }, - }, - }, - "migrations": Object {}, - "name": "typeC", - "namespaceType": "single", - }, - Object { - "convertToAliasScript": undefined, - "hidden": false, - "indexPattern": "bazQux", - "management": undefined, - "mappings": Object { - "properties": Object { - "fieldD": Object { - "type": "text", - }, - }, - }, - "migrations": Object {}, - "name": "typeD", - "namespaceType": "agnostic", - }, -] -`; diff --git a/src/core/server/saved_objects/index.ts b/src/core/server/saved_objects/index.ts index a294b28753f7..f2bae29c4743 100644 --- a/src/core/server/saved_objects/index.ts +++ b/src/core/server/saved_objects/index.ts @@ -19,8 +19,6 @@ export * from './service'; -export { SavedObjectsSchema } from './schema'; - export * from './import'; export { diff --git a/src/core/server/saved_objects/migrations/core/document_migrator.test.ts b/src/core/server/saved_objects/migrations/core/document_migrator.test.ts index 4fc94d199286..4cc4f696d307 100644 --- a/src/core/server/saved_objects/migrations/core/document_migrator.test.ts +++ b/src/core/server/saved_objects/migrations/core/document_migrator.test.ts @@ -48,7 +48,6 @@ describe('DocumentMigrator', () => { return { kibanaVersion: '25.2.3', typeRegistry: createRegistry(), - validateDoc: _.noop, log: mockLogger, }; } @@ -60,7 +59,6 @@ describe('DocumentMigrator', () => { name: 'foo', migrations: _.noop as any, }), - validateDoc: _.noop, log: mockLogger, }; expect(() => new DocumentMigrator(invalidDefinition)).toThrow( @@ -77,7 +75,6 @@ describe('DocumentMigrator', () => { bar: (doc) => doc, }, }), - validateDoc: _.noop, log: mockLogger, }; expect(() => new DocumentMigrator(invalidDefinition)).toThrow( @@ -94,7 +91,6 @@ describe('DocumentMigrator', () => { '1.2.3': 23 as any, }, }), - validateDoc: _.noop, log: mockLogger, }; expect(() => new DocumentMigrator(invalidDefinition)).toThrow( @@ -633,27 +629,6 @@ describe('DocumentMigrator', () => { bbb: '3.2.3', }); }); - - test('fails if the validate doc throws', () => { - const migrator = new DocumentMigrator({ - ...testOpts(), - typeRegistry: createRegistry({ - name: 'aaa', - migrations: { - '2.3.4': (d) => set(d, 'attributes.counter', 42), - }, - }), - validateDoc: (d) => { - if ((d.attributes as any).counter === 42) { - throw new Error('Meaningful!'); - } - }, - }); - - const doc = { id: '1', type: 'foo', attributes: {}, migrationVersion: {}, aaa: {} }; - - expect(() => migrator.migrate(doc)).toThrow(/Meaningful/); - }); }); function renameAttr(path: string, newPath: string) { diff --git a/src/core/server/saved_objects/migrations/core/document_migrator.ts b/src/core/server/saved_objects/migrations/core/document_migrator.ts index c50f755fda99..345704fbfd78 100644 --- a/src/core/server/saved_objects/migrations/core/document_migrator.ts +++ b/src/core/server/saved_objects/migrations/core/document_migrator.ts @@ -73,12 +73,9 @@ import { SavedObjectMigrationFn } from '../types'; export type TransformFn = (doc: SavedObjectUnsanitizedDoc) => SavedObjectUnsanitizedDoc; -type ValidateDoc = (doc: SavedObjectUnsanitizedDoc) => void; - interface DocumentMigratorOptions { kibanaVersion: string; typeRegistry: ISavedObjectTypeRegistry; - validateDoc: ValidateDoc; log: Logger; } @@ -113,19 +110,16 @@ export class DocumentMigrator implements VersionedTransformer { * @param {DocumentMigratorOptions} opts * @prop {string} kibanaVersion - The current version of Kibana * @prop {SavedObjectTypeRegistry} typeRegistry - The type registry to get type migrations from - * @prop {ValidateDoc} validateDoc - A function which, given a document throws an error if it is - * not up to date. This is used to ensure we don't let unmigrated documents slip through. * @prop {Logger} log - The migration logger * @memberof DocumentMigrator */ - constructor({ typeRegistry, kibanaVersion, log, validateDoc }: DocumentMigratorOptions) { + constructor({ typeRegistry, kibanaVersion, log }: DocumentMigratorOptions) { validateMigrationDefinition(typeRegistry); this.migrations = buildActiveMigrations(typeRegistry, log); this.transformDoc = buildDocumentTransform({ kibanaVersion, migrations: this.migrations, - validateDoc, }); } @@ -231,21 +225,16 @@ function buildActiveMigrations( * Creates a function which migrates and validates any document that is passed to it. */ function buildDocumentTransform({ - kibanaVersion, migrations, - validateDoc, }: { kibanaVersion: string; migrations: ActiveMigrations; - validateDoc: ValidateDoc; }): TransformFn { return function transformAndValidate(doc: SavedObjectUnsanitizedDoc) { const result = doc.migrationVersion ? applyMigrations(doc, migrations) : markAsUpToDate(doc, migrations); - validateDoc(result); - // In order to keep tests a bit more stable, we won't // tack on an empy migrationVersion to docs that have // no migrations defined. diff --git a/src/core/server/saved_objects/migrations/core/index_migrator.test.ts b/src/core/server/saved_objects/migrations/core/index_migrator.test.ts index df89137a1d79..13f771c16bc6 100644 --- a/src/core/server/saved_objects/migrations/core/index_migrator.test.ts +++ b/src/core/server/saved_objects/migrations/core/index_migrator.test.ts @@ -369,6 +369,30 @@ describe('IndexMigrator', () => { ], }); }); + + test('rejects when the migration function throws an error', async () => { + const { client } = testOpts; + const migrateDoc = jest.fn((doc: SavedObjectUnsanitizedDoc) => { + throw new Error('error migrating document'); + }); + + testOpts.documentMigrator = { + migrationVersion: { foo: '1.2.3' }, + migrate: migrateDoc, + }; + + withIndex(client, { + numOutOfDate: 1, + docs: [ + [{ _id: 'foo:1', _source: { type: 'foo', foo: { name: 'Bar' } } }], + [{ _id: 'foo:2', _source: { type: 'foo', foo: { name: 'Baz' } } }], + ], + }); + + await expect(new IndexMigrator(testOpts).migrate()).rejects.toThrowErrorMatchingInlineSnapshot( + `"error migrating document"` + ); + }); }); function withIndex( diff --git a/src/core/server/saved_objects/migrations/core/migrate_raw_docs.test.ts b/src/core/server/saved_objects/migrations/core/migrate_raw_docs.test.ts index 4c9d2e870a7b..83dc042d2b96 100644 --- a/src/core/server/saved_objects/migrations/core/migrate_raw_docs.test.ts +++ b/src/core/server/saved_objects/migrations/core/migrate_raw_docs.test.ts @@ -90,4 +90,18 @@ describe('migrateRawDocs', () => { expect(logger.error).toBeCalledTimes(1); }); + + test('rejects when the transform function throws an error', async () => { + const transform = jest.fn((doc: any) => { + throw new Error('error during transform'); + }); + await expect( + migrateRawDocs( + new SavedObjectsSerializer(new SavedObjectTypeRegistry()), + transform, + [{ _id: 'a:b', _source: { type: 'a', a: { name: 'AAA' } } }], + createSavedObjectsMigrationLoggerMock() + ) + ).rejects.toThrowErrorMatchingInlineSnapshot(`"error during transform"`); + }); }); diff --git a/src/core/server/saved_objects/migrations/core/migrate_raw_docs.ts b/src/core/server/saved_objects/migrations/core/migrate_raw_docs.ts index 2bdf59d25dc7..5a5048d8ad88 100644 --- a/src/core/server/saved_objects/migrations/core/migrate_raw_docs.ts +++ b/src/core/server/saved_objects/migrations/core/migrate_raw_docs.ts @@ -78,10 +78,14 @@ function transformNonBlocking( ): (doc: SavedObjectUnsanitizedDoc) => Promise { // promises aren't enough to unblock the event loop return (doc: SavedObjectUnsanitizedDoc) => - new Promise((resolve) => { + new Promise((resolve, reject) => { // set immediate is though setImmediate(() => { - resolve(transform(doc)); + try { + resolve(transform(doc)); + } catch (e) { + reject(e); + } }); }); } diff --git a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts index cc443093e30a..7eb2cfefe462 100644 --- a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts +++ b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.test.ts @@ -134,7 +134,6 @@ const mockOptions = () => { const options: MockedOptions = { logger: loggingSystemMock.create().get(), kibanaVersion: '8.2.3', - savedObjectValidations: {}, typeRegistry: createRegistry([ { name: 'testtype', diff --git a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts index 85b909930880..18a385c6994b 100644 --- a/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts +++ b/src/core/server/saved_objects/migrations/kibana/kibana_migrator.ts @@ -28,7 +28,6 @@ import { BehaviorSubject } from 'rxjs'; import { Logger } from '../../../logging'; import { IndexMapping, SavedObjectsTypeMappingDefinitions } from '../../mappings'; import { SavedObjectUnsanitizedDoc, SavedObjectsSerializer } from '../../serialization'; -import { docValidator, PropertyValidators } from '../../validation'; import { buildActiveMappings, IndexMigrator, MigrationResult, MigrationStatus } from '../core'; import { DocumentMigrator, VersionedTransformer } from '../core/document_migrator'; import { MigrationEsClient } from '../core/'; @@ -44,7 +43,6 @@ export interface KibanaMigratorOptions { kibanaConfig: KibanaConfigType; kibanaVersion: string; logger: Logger; - savedObjectValidations: PropertyValidators; } export type IKibanaMigrator = Pick; @@ -80,7 +78,6 @@ export class KibanaMigrator { typeRegistry, kibanaConfig, savedObjectsConfig, - savedObjectValidations, kibanaVersion, logger, }: KibanaMigratorOptions) { @@ -94,7 +91,6 @@ export class KibanaMigrator { this.documentMigrator = new DocumentMigrator({ kibanaVersion, typeRegistry, - validateDoc: docValidator(savedObjectValidations || {}), log: this.log, }); // Building the active mappings (and associated md5sums) is an expensive @@ -124,9 +120,17 @@ export class KibanaMigrator { Array<{ status: string }> > { if (this.migrationResult === undefined || rerun) { - this.status$.next({ status: 'running' }); + // Reruns are only used by CI / EsArchiver. Publishing status updates on reruns results in slowing down CI + // unnecessarily, so we skip it in this case. + if (!rerun) { + this.status$.next({ status: 'running' }); + } + this.migrationResult = this.runMigrationsInternal().then((result) => { - this.status$.next({ status: 'completed', result }); + // Similar to above, don't publish status updates when rerunning in CI. + if (!rerun) { + this.status$.next({ status: 'completed', result }); + } return result; }); } diff --git a/src/core/server/saved_objects/saved_objects_service.mock.ts b/src/core/server/saved_objects/saved_objects_service.mock.ts index 6f5ecb1eb464..e3d44c20dd19 100644 --- a/src/core/server/saved_objects/saved_objects_service.mock.ts +++ b/src/core/server/saved_objects/saved_objects_service.mock.ts @@ -26,8 +26,7 @@ import { SavedObjectsServiceSetup, SavedObjectsServiceStart, } from './saved_objects_service'; -import { mockKibanaMigrator } from './migrations/kibana/kibana_migrator.mock'; -import { savedObjectsClientProviderMock } from './service/lib/scoped_client_provider.mock'; + import { savedObjectsRepositoryMock } from './service/lib/repository.mock'; import { savedObjectsClientMock } from './service/saved_objects_client.mock'; import { typeRegistryMock } from './saved_objects_type_registry.mock'; @@ -54,11 +53,7 @@ const createStartContractMock = () => { }; const createInternalStartContractMock = () => { - const internalStartContract: jest.Mocked = { - ...createStartContractMock(), - clientProvider: savedObjectsClientProviderMock.create(), - migrator: mockKibanaMigrator.create(), - }; + const internalStartContract: jest.Mocked = createStartContractMock(); return internalStartContract; }; diff --git a/src/core/server/saved_objects/saved_objects_service.test.ts b/src/core/server/saved_objects/saved_objects_service.test.ts index 8df6a07318c4..d6b30889eba5 100644 --- a/src/core/server/saved_objects/saved_objects_service.test.ts +++ b/src/core/server/saved_objects/saved_objects_service.test.ts @@ -33,7 +33,6 @@ import { Env } from '../config'; import { configServiceMock } from '../mocks'; import { elasticsearchServiceMock } from '../elasticsearch/elasticsearch_service.mock'; import { elasticsearchClientMock } from '../elasticsearch/client/mocks'; -import { legacyServiceMock } from '../legacy/legacy_service.mock'; import { httpServiceMock } from '../http/http_service.mock'; import { httpServerMock } from '../http/http_server.mocks'; import { SavedObjectsClientFactoryProvider } from './service/lib'; @@ -65,7 +64,6 @@ describe('SavedObjectsService', () => { return { http: httpServiceMock.createInternalSetupContract(), elasticsearch: elasticsearchMock, - legacyPlugins: legacyServiceMock.createDiscoverPlugins(), }; }; @@ -239,8 +237,7 @@ describe('SavedObjectsService', () => { await soService.setup(createSetupDeps()); expect(migratorInstanceMock.runMigrations).toHaveBeenCalledTimes(0); - const startContract = await soService.start(createStartDeps()); - expect(startContract.migrator).toBe(migratorInstanceMock); + await soService.start(createStartDeps()); expect(migratorInstanceMock.runMigrations).toHaveBeenCalledTimes(1); }); diff --git a/src/core/server/saved_objects/saved_objects_service.ts b/src/core/server/saved_objects/saved_objects_service.ts index f05e912b12ad..5cc59d55a254 100644 --- a/src/core/server/saved_objects/saved_objects_service.ts +++ b/src/core/server/saved_objects/saved_objects_service.ts @@ -23,12 +23,10 @@ import { CoreService } from '../../types'; import { SavedObjectsClient, SavedObjectsClientProvider, - ISavedObjectsClientProvider, SavedObjectsClientProviderOptions, } from './'; import { KibanaMigrator, IKibanaMigrator } from './migrations'; import { CoreContext } from '../core_context'; -import { LegacyServiceDiscoverPlugins } from '../legacy'; import { ElasticsearchClient, IClusterClient, @@ -49,9 +47,7 @@ import { SavedObjectsClientWrapperFactory, } from './service/lib/scoped_client_provider'; import { Logger } from '../logging'; -import { convertLegacyTypes } from './utils'; import { SavedObjectTypeRegistry, ISavedObjectTypeRegistry } from './saved_objects_type_registry'; -import { PropertyValidators } from './validation'; import { SavedObjectsSerializer } from './serialization'; import { registerRoutes } from './routes'; import { ServiceStatus } from '../status'; @@ -67,9 +63,6 @@ import { createMigrationEsClient } from './migrations/core/'; * the factory provided to `setClientFactory` and wrapped by all wrappers * registered through `addClientWrapper`. * - * All the setup APIs will throw if called after the service has started, and therefor cannot be used - * from legacy plugin code. Legacy plugins should use the legacy savedObject service until migrated. - * * @example * ```ts * import { SavedObjectsClient, CoreSetup } from 'src/core/server'; @@ -155,9 +148,6 @@ export interface SavedObjectsServiceSetup { * } * } * ``` - * - * @remarks The type definition is an aggregation of the legacy savedObjects `schema`, `mappings` and `migration` concepts. - * This API is the single entry point to register saved object types in the new platform. */ registerType: (type: SavedObjectsType) => void; @@ -230,16 +220,7 @@ export interface SavedObjectsServiceStart { getTypeRegistry: () => ISavedObjectTypeRegistry; } -export interface InternalSavedObjectsServiceStart extends SavedObjectsServiceStart { - /** - * @deprecated Exposed only for injecting into Legacy - */ - migrator: IKibanaMigrator; - /** - * @deprecated Exposed only for injecting into Legacy - */ - clientProvider: ISavedObjectsClientProvider; -} +export type InternalSavedObjectsServiceStart = SavedObjectsServiceStart; /** * Factory provided when invoking a {@link SavedObjectsClientFactoryProvider | client factory provider} @@ -271,7 +252,6 @@ export interface SavedObjectsRepositoryFactory { /** @internal */ export interface SavedObjectsSetupDeps { http: InternalHttpServiceSetup; - legacyPlugins: LegacyServiceDiscoverPlugins; elasticsearch: InternalElasticsearchServiceSetup; } @@ -296,9 +276,8 @@ export class SavedObjectsService private clientFactoryProvider?: SavedObjectsClientFactoryProvider; private clientFactoryWrappers: WrappedClientFactoryWrapper[] = []; - private migrator$ = new Subject(); + private migrator$ = new Subject(); private typeRegistry = new SavedObjectTypeRegistry(); - private validations: PropertyValidators = {}; private started = false; constructor(private readonly coreContext: CoreContext) { @@ -310,13 +289,6 @@ export class SavedObjectsService this.setupDeps = setupDeps; - const legacyTypes = convertLegacyTypes( - setupDeps.legacyPlugins.uiExports, - setupDeps.legacyPlugins.pluginExtendedConfig - ); - legacyTypes.forEach((type) => this.typeRegistry.registerType(type)); - this.validations = setupDeps.legacyPlugins.uiExports.savedObjectValidations || {}; - const savedObjectsConfig = await this.coreContext.configService .atPath('savedObjects') .pipe(first()) @@ -471,8 +443,6 @@ export class SavedObjectsService this.started = true; return { - migrator, - clientProvider, getScopedClient: clientProvider.getClient.bind(clientProvider), createScopedRepository: repositoryFactory.createScopedRepository, createInternalRepository: repositoryFactory.createInternalRepository, @@ -488,13 +458,12 @@ export class SavedObjectsService savedObjectsConfig: SavedObjectsMigrationConfigType, client: IClusterClient, migrationsRetryDelay?: number - ): KibanaMigrator { + ): IKibanaMigrator { return new KibanaMigrator({ typeRegistry: this.typeRegistry, logger: this.logger, kibanaVersion: this.coreContext.env.packageInfo.version, savedObjectsConfig, - savedObjectValidations: this.validations, kibanaConfig, client: createMigrationEsClient(client.asInternalUser, this.logger, migrationsRetryDelay), }); diff --git a/src/core/server/saved_objects/schema/schema.test.ts b/src/core/server/saved_objects/schema/schema.test.ts deleted file mode 100644 index f2daa13e43fc..000000000000 --- a/src/core/server/saved_objects/schema/schema.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { SavedObjectsSchema, SavedObjectsSchemaDefinition } from './schema'; - -describe('#isNamespaceAgnostic', () => { - const expectResult = (expected: boolean, schemaDefinition?: SavedObjectsSchemaDefinition) => { - const schema = new SavedObjectsSchema(schemaDefinition); - const result = schema.isNamespaceAgnostic('foo'); - expect(result).toBe(expected); - }; - - it(`returns false when no schema is defined`, () => { - expectResult(false); - }); - - it(`returns false for unknown types`, () => { - expectResult(false, { bar: {} }); - }); - - it(`returns false for non-namespace-agnostic type`, () => { - expectResult(false, { foo: { isNamespaceAgnostic: false } }); - expectResult(false, { foo: { isNamespaceAgnostic: undefined } }); - }); - - it(`returns true for explicitly namespace-agnostic type`, () => { - expectResult(true, { foo: { isNamespaceAgnostic: true } }); - }); -}); - -describe('#isSingleNamespace', () => { - const expectResult = (expected: boolean, schemaDefinition?: SavedObjectsSchemaDefinition) => { - const schema = new SavedObjectsSchema(schemaDefinition); - const result = schema.isSingleNamespace('foo'); - expect(result).toBe(expected); - }; - - it(`returns true when no schema is defined`, () => { - expectResult(true); - }); - - it(`returns true for unknown types`, () => { - expectResult(true, { bar: {} }); - }); - - it(`returns false for explicitly namespace-agnostic type`, () => { - expectResult(false, { foo: { isNamespaceAgnostic: true } }); - }); - - it(`returns false for explicitly multi-namespace type`, () => { - expectResult(false, { foo: { multiNamespace: true } }); - }); - - it(`returns true for non-namespace-agnostic and non-multi-namespace type`, () => { - expectResult(true, { foo: { isNamespaceAgnostic: false, multiNamespace: false } }); - expectResult(true, { foo: { isNamespaceAgnostic: false, multiNamespace: undefined } }); - expectResult(true, { foo: { isNamespaceAgnostic: undefined, multiNamespace: false } }); - expectResult(true, { foo: { isNamespaceAgnostic: undefined, multiNamespace: undefined } }); - }); -}); - -describe('#isMultiNamespace', () => { - const expectResult = (expected: boolean, schemaDefinition?: SavedObjectsSchemaDefinition) => { - const schema = new SavedObjectsSchema(schemaDefinition); - const result = schema.isMultiNamespace('foo'); - expect(result).toBe(expected); - }; - - it(`returns false when no schema is defined`, () => { - expectResult(false); - }); - - it(`returns false for unknown types`, () => { - expectResult(false, { bar: {} }); - }); - - it(`returns false for explicitly namespace-agnostic type`, () => { - expectResult(false, { foo: { isNamespaceAgnostic: true } }); - }); - - it(`returns false for non-multi-namespace type`, () => { - expectResult(false, { foo: { multiNamespace: false } }); - expectResult(false, { foo: { multiNamespace: undefined } }); - }); - - it(`returns true for non-namespace-agnostic and explicitly multi-namespace type`, () => { - expectResult(true, { foo: { isNamespaceAgnostic: false, multiNamespace: true } }); - expectResult(true, { foo: { isNamespaceAgnostic: undefined, multiNamespace: true } }); - }); -}); diff --git a/src/core/server/saved_objects/schema/schema.ts b/src/core/server/saved_objects/schema/schema.ts deleted file mode 100644 index ba1905158e82..000000000000 --- a/src/core/server/saved_objects/schema/schema.ts +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { LegacyConfig } from '../../legacy'; - -/** - * @deprecated - * @internal - **/ -interface SavedObjectsSchemaTypeDefinition { - isNamespaceAgnostic?: boolean; - multiNamespace?: boolean; - hidden?: boolean; - indexPattern?: ((config: LegacyConfig) => string) | string; - convertToAliasScript?: string; -} - -/** - * @deprecated - * @internal - **/ -export interface SavedObjectsSchemaDefinition { - [type: string]: SavedObjectsSchemaTypeDefinition; -} - -/** - * @deprecated This is only used by the {@link SavedObjectsLegacyService | legacy savedObjects service} - * @internal - **/ -export class SavedObjectsSchema { - private readonly definition?: SavedObjectsSchemaDefinition; - constructor(schemaDefinition?: SavedObjectsSchemaDefinition) { - this.definition = schemaDefinition; - } - - public isHiddenType(type: string) { - if (this.definition && this.definition.hasOwnProperty(type)) { - return Boolean(this.definition[type].hidden); - } - - return false; - } - - public getIndexForType(config: LegacyConfig, type: string): string | undefined { - if (this.definition != null && this.definition.hasOwnProperty(type)) { - const { indexPattern } = this.definition[type]; - return typeof indexPattern === 'function' ? indexPattern(config) : indexPattern; - } else { - return undefined; - } - } - - public getConvertToAliasScript(type: string): string | undefined { - if (this.definition != null && this.definition.hasOwnProperty(type)) { - return this.definition[type].convertToAliasScript; - } - } - - public isNamespaceAgnostic(type: string) { - // if no plugins have registered a Saved Objects Schema, - // this.schema will be undefined, and no types are namespace agnostic - if (!this.definition) { - return false; - } - - const typeSchema = this.definition[type]; - if (!typeSchema) { - return false; - } - return Boolean(typeSchema.isNamespaceAgnostic); - } - - public isSingleNamespace(type: string) { - // if no plugins have registered a Saved Objects Schema, - // this.schema will be undefined, and all types are namespace isolated - if (!this.definition) { - return true; - } - - const typeSchema = this.definition[type]; - if (!typeSchema) { - return true; - } - return !Boolean(typeSchema.isNamespaceAgnostic) && !Boolean(typeSchema.multiNamespace); - } - - public isMultiNamespace(type: string) { - // if no plugins have registered a Saved Objects Schema, - // this.schema will be undefined, and no types are multi-namespace - if (!this.definition) { - return false; - } - - const typeSchema = this.definition[type]; - if (!typeSchema) { - return false; - } - return !Boolean(typeSchema.isNamespaceAgnostic) && Boolean(typeSchema.multiNamespace); - } -} diff --git a/src/core/server/saved_objects/service/index.ts b/src/core/server/saved_objects/service/index.ts index 9f625b4732e2..271d4dd67d43 100644 --- a/src/core/server/saved_objects/service/index.ts +++ b/src/core/server/saved_objects/service/index.ts @@ -17,37 +17,6 @@ * under the License. */ -import { Readable } from 'stream'; -import { SavedObjectsClientProvider } from './lib'; -import { SavedObjectsClient } from './saved_objects_client'; -import { SavedObjectsExportOptions } from '../export'; -import { SavedObjectsImportOptions, SavedObjectsImportResponse } from '../import'; -import { SavedObjectsSchema } from '../schema'; -import { SavedObjectsResolveImportErrorsOptions } from '../import/types'; - -/** - * @internal - * @deprecated - */ -export interface SavedObjectsLegacyService { - // ATTENTION: these types are incomplete - addScopedSavedObjectsClientWrapperFactory: SavedObjectsClientProvider['addClientWrapperFactory']; - setScopedSavedObjectsClientFactory: SavedObjectsClientProvider['setClientFactory']; - getScopedSavedObjectsClient: SavedObjectsClientProvider['getClient']; - SavedObjectsClient: typeof SavedObjectsClient; - types: string[]; - schema: SavedObjectsSchema; - getSavedObjectsRepository(...rest: any[]): any; - importExport: { - objectLimit: number; - importSavedObjects(options: SavedObjectsImportOptions): Promise; - resolveImportErrors( - options: SavedObjectsResolveImportErrorsOptions - ): Promise; - getSortedObjectsForExport(options: SavedObjectsExportOptions): Promise; - }; -} - export { SavedObjectsRepository, SavedObjectsClientProvider, diff --git a/src/core/server/saved_objects/service/lib/repository.test.js b/src/core/server/saved_objects/service/lib/repository.test.js index b1d602846571..f2e3b3e633cd 100644 --- a/src/core/server/saved_objects/service/lib/repository.test.js +++ b/src/core/server/saved_objects/service/lib/repository.test.js @@ -153,7 +153,6 @@ describe('SavedObjectsRepository', () => { typeRegistry: registry, kibanaVersion: '2.0.0', log: {}, - validateDoc: jest.fn(), }); const getMockGetResponse = ({ type, id, references, namespace, originId }) => ({ diff --git a/src/core/server/saved_objects/service/lib/repository.ts b/src/core/server/saved_objects/service/lib/repository.ts index dd25989725f3..e3fb7d230646 100644 --- a/src/core/server/saved_objects/service/lib/repository.ts +++ b/src/core/server/saved_objects/service/lib/repository.ts @@ -31,7 +31,7 @@ import { getSearchDsl } from './search_dsl'; import { includedFields } from './included_fields'; import { SavedObjectsErrorHelpers, DecoratedError } from './errors'; import { decodeRequestVersion, encodeVersion, encodeHitVersion } from '../../version'; -import { KibanaMigrator } from '../../migrations'; +import { IKibanaMigrator } from '../../migrations'; import { SavedObjectsSerializer, SavedObjectSanitizedDoc, @@ -85,7 +85,7 @@ export interface SavedObjectsRepositoryOptions { client: ElasticsearchClient; typeRegistry: SavedObjectTypeRegistry; serializer: SavedObjectsSerializer; - migrator: KibanaMigrator; + migrator: IKibanaMigrator; allowedTypes: string[]; } @@ -120,7 +120,7 @@ export type ISavedObjectsRepository = Pick) => { path: string; uiCapabilitiesPath: string }; } - -/** - * @internal - * @deprecated - */ -export interface SavedObjectsLegacyUiExports { - savedObjectMappings: SavedObjectsLegacyMapping[]; - savedObjectMigrations: SavedObjectsLegacyMigrationDefinitions; - savedObjectSchemas: SavedObjectsLegacySchemaDefinitions; - savedObjectValidations: PropertyValidators; - savedObjectsManagement: SavedObjectsLegacyManagementDefinition; -} - -/** - * @internal - * @deprecated - */ -export interface SavedObjectsLegacyMapping { - pluginId: string; - properties: SavedObjectsTypeMappingDefinitions; -} - -/** - * @internal - * @deprecated Use {@link SavedObjectsTypeManagementDefinition | management definition} when registering - * from new platform plugins - */ -export interface SavedObjectsLegacyManagementDefinition { - [key: string]: SavedObjectsLegacyManagementTypeDefinition; -} - -/** - * @internal - * @deprecated - */ -export interface SavedObjectsLegacyManagementTypeDefinition { - isImportableAndExportable?: boolean; - defaultSearchField?: string; - icon?: string; - getTitle?: (savedObject: SavedObject) => string; - getEditUrl?: (savedObject: SavedObject) => string; - getInAppUrl?: (savedObject: SavedObject) => { path: string; uiCapabilitiesPath: string }; -} - -/** - * @internal - * @deprecated - */ -export interface SavedObjectsLegacyMigrationDefinitions { - [type: string]: SavedObjectLegacyMigrationMap; -} - -/** - * @internal - * @deprecated - */ -export interface SavedObjectLegacyMigrationMap { - [version: string]: SavedObjectLegacyMigrationFn; -} - -/** - * @internal - * @deprecated - */ -export type SavedObjectLegacyMigrationFn = ( - doc: SavedObjectUnsanitizedDoc, - log: SavedObjectsMigrationLogger -) => SavedObjectUnsanitizedDoc; - -/** - * @internal - * @deprecated - */ -interface SavedObjectsLegacyTypeSchema { - isNamespaceAgnostic?: boolean; - /** Cannot be used in conjunction with `isNamespaceAgnostic` */ - multiNamespace?: boolean; - hidden?: boolean; - indexPattern?: ((config: LegacyConfig) => string) | string; - convertToAliasScript?: string; -} - -/** - * @internal - * @deprecated - */ -export interface SavedObjectsLegacySchemaDefinitions { - [type: string]: SavedObjectsLegacyTypeSchema; -} diff --git a/src/core/server/saved_objects/utils.test.ts b/src/core/server/saved_objects/utils.test.ts deleted file mode 100644 index 21229bee489c..000000000000 --- a/src/core/server/saved_objects/utils.test.ts +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { legacyServiceMock } from '../legacy/legacy_service.mock'; -import { convertLegacyTypes, convertTypesToLegacySchema } from './utils'; -import { SavedObjectsLegacyUiExports, SavedObjectsType } from './types'; -import { LegacyConfig, SavedObjectMigrationContext } from 'kibana/server'; -import { SavedObjectUnsanitizedDoc } from './serialization'; - -describe('convertLegacyTypes', () => { - let legacyConfig: ReturnType; - - beforeEach(() => { - legacyConfig = legacyServiceMock.createLegacyConfig(); - }); - - it('converts the legacy mappings using default values if no schemas are specified', () => { - const uiExports: SavedObjectsLegacyUiExports = { - savedObjectMappings: [ - { - pluginId: 'pluginA', - properties: { - typeA: { - properties: { - fieldA: { type: 'text' }, - }, - }, - typeB: { - properties: { - fieldB: { type: 'text' }, - }, - }, - }, - }, - { - pluginId: 'pluginB', - properties: { - typeC: { - properties: { - fieldC: { type: 'text' }, - }, - }, - }, - }, - ], - savedObjectMigrations: {}, - savedObjectSchemas: {}, - savedObjectValidations: {}, - savedObjectsManagement: {}, - }; - - const converted = convertLegacyTypes(uiExports, legacyConfig); - expect(converted).toMatchSnapshot(); - }); - - it('merges the mappings and the schema to create the type when schema exists for the type', () => { - const uiExports: SavedObjectsLegacyUiExports = { - savedObjectMappings: [ - { - pluginId: 'pluginA', - properties: { - typeA: { - properties: { - fieldA: { type: 'text' }, - }, - }, - }, - }, - { - pluginId: 'pluginB', - properties: { - typeB: { - properties: { - fieldB: { type: 'text' }, - }, - }, - }, - }, - { - pluginId: 'pluginC', - properties: { - typeC: { - properties: { - fieldC: { type: 'text' }, - }, - }, - }, - }, - { - pluginId: 'pluginD', - properties: { - typeD: { - properties: { - fieldD: { type: 'text' }, - }, - }, - }, - }, - ], - savedObjectMigrations: {}, - savedObjectSchemas: { - typeA: { - indexPattern: 'fooBar', - hidden: true, - isNamespaceAgnostic: true, - }, - typeB: { - indexPattern: 'barBaz', - hidden: false, - multiNamespace: true, - }, - typeD: { - indexPattern: 'bazQux', - hidden: false, - // if both isNamespaceAgnostic and multiNamespace are true, the resulting namespaceType is 'agnostic' - isNamespaceAgnostic: true, - multiNamespace: true, - }, - }, - savedObjectValidations: {}, - savedObjectsManagement: {}, - }; - - const converted = convertLegacyTypes(uiExports, legacyConfig); - expect(converted).toMatchSnapshot(); - }); - - it('invokes indexPattern to retrieve the index when it is a function', () => { - const indexPatternAccessor: (config: LegacyConfig) => string = jest.fn((config) => { - config.get('foo.bar'); - return 'myIndex'; - }); - - const uiExports: SavedObjectsLegacyUiExports = { - savedObjectMappings: [ - { - pluginId: 'pluginA', - properties: { - typeA: { - properties: { - fieldA: { type: 'text' }, - }, - }, - }, - }, - ], - savedObjectMigrations: {}, - savedObjectSchemas: { - typeA: { - indexPattern: indexPatternAccessor, - hidden: true, - isNamespaceAgnostic: true, - }, - }, - savedObjectValidations: {}, - savedObjectsManagement: {}, - }; - - const converted = convertLegacyTypes(uiExports, legacyConfig); - - expect(indexPatternAccessor).toHaveBeenCalledWith(legacyConfig); - expect(legacyConfig.get).toHaveBeenCalledWith('foo.bar'); - expect(converted.length).toEqual(1); - expect(converted[0].indexPattern).toEqual('myIndex'); - }); - - it('import migrations from the uiExports', () => { - const migrationsA = { - '1.0.0': jest.fn(), - '2.0.4': jest.fn(), - }; - const migrationsB = { - '1.5.3': jest.fn(), - }; - - const uiExports: SavedObjectsLegacyUiExports = { - savedObjectMappings: [ - { - pluginId: 'pluginA', - properties: { - typeA: { - properties: { - fieldA: { type: 'text' }, - }, - }, - }, - }, - { - pluginId: 'pluginB', - properties: { - typeB: { - properties: { - fieldC: { type: 'text' }, - }, - }, - }, - }, - ], - savedObjectMigrations: { - typeA: migrationsA, - typeB: migrationsB, - }, - savedObjectSchemas: {}, - savedObjectValidations: {}, - savedObjectsManagement: {}, - }; - - const converted = convertLegacyTypes(uiExports, legacyConfig); - expect(converted.length).toEqual(2); - expect(Object.keys(converted[0]!.migrations!)).toEqual(Object.keys(migrationsA)); - expect(Object.keys(converted[1]!.migrations!)).toEqual(Object.keys(migrationsB)); - }); - - it('converts the migration to the new format', () => { - const legacyMigration = jest.fn(); - const migrationsA = { - '1.0.0': legacyMigration, - }; - - const uiExports: SavedObjectsLegacyUiExports = { - savedObjectMappings: [ - { - pluginId: 'pluginA', - properties: { - typeA: { - properties: { - fieldA: { type: 'text' }, - }, - }, - }, - }, - ], - savedObjectMigrations: { - typeA: migrationsA, - }, - savedObjectSchemas: {}, - savedObjectValidations: {}, - savedObjectsManagement: {}, - }; - - const converted = convertLegacyTypes(uiExports, legacyConfig); - expect(Object.keys(converted[0]!.migrations!)).toEqual(['1.0.0']); - - const migration = converted[0]!.migrations!['1.0.0']!; - - const doc = {} as SavedObjectUnsanitizedDoc; - const context = { log: {} } as SavedObjectMigrationContext; - migration(doc, context); - - expect(legacyMigration).toHaveBeenCalledTimes(1); - expect(legacyMigration).toHaveBeenCalledWith(doc, context.log); - }); - - it('imports type management information', () => { - const uiExports: SavedObjectsLegacyUiExports = { - savedObjectMappings: [ - { - pluginId: 'pluginA', - properties: { - typeA: { - properties: { - fieldA: { type: 'text' }, - }, - }, - }, - }, - { - pluginId: 'pluginB', - properties: { - typeB: { - properties: { - fieldB: { type: 'text' }, - }, - }, - typeC: { - properties: { - fieldC: { type: 'text' }, - }, - }, - }, - }, - ], - savedObjectsManagement: { - typeA: { - isImportableAndExportable: true, - icon: 'iconA', - defaultSearchField: 'searchFieldA', - getTitle: (savedObject) => savedObject.id, - }, - typeB: { - isImportableAndExportable: false, - icon: 'iconB', - getEditUrl: (savedObject) => `/some-url/${savedObject.id}`, - getInAppUrl: (savedObject) => ({ path: 'path', uiCapabilitiesPath: 'ui-path' }), - }, - }, - savedObjectMigrations: {}, - savedObjectSchemas: {}, - savedObjectValidations: {}, - }; - - const converted = convertLegacyTypes(uiExports, legacyConfig); - expect(converted.length).toEqual(3); - const [typeA, typeB, typeC] = converted; - - expect(typeA.management).toEqual({ - importableAndExportable: true, - icon: 'iconA', - defaultSearchField: 'searchFieldA', - getTitle: uiExports.savedObjectsManagement.typeA.getTitle, - }); - - expect(typeB.management).toEqual({ - importableAndExportable: false, - icon: 'iconB', - getEditUrl: uiExports.savedObjectsManagement.typeB.getEditUrl, - getInAppUrl: uiExports.savedObjectsManagement.typeB.getInAppUrl, - }); - - expect(typeC.management).toBeUndefined(); - }); - - it('merges everything when all are present', () => { - const uiExports: SavedObjectsLegacyUiExports = { - savedObjectMappings: [ - { - pluginId: 'pluginA', - properties: { - typeA: { - properties: { - fieldA: { type: 'text' }, - }, - }, - typeB: { - properties: { - fieldB: { type: 'text' }, - anotherFieldB: { type: 'boolean' }, - }, - }, - }, - }, - { - pluginId: 'pluginB', - properties: { - typeC: { - properties: { - fieldC: { type: 'text' }, - }, - }, - }, - }, - ], - savedObjectMigrations: { - typeA: { - '1.0.0': jest.fn(), - '2.0.4': jest.fn(), - }, - typeC: { - '1.5.3': jest.fn(), - }, - }, - savedObjectSchemas: { - typeA: { - indexPattern: jest.fn((config) => { - config.get('foo.bar'); - return 'myIndex'; - }), - hidden: true, - isNamespaceAgnostic: true, - }, - typeB: { - convertToAliasScript: 'some alias script', - hidden: false, - }, - }, - savedObjectValidations: {}, - savedObjectsManagement: {}, - }; - - const converted = convertLegacyTypes(uiExports, legacyConfig); - expect(converted).toMatchSnapshot(); - }); -}); - -describe('convertTypesToLegacySchema', () => { - it('converts types to the legacy schema format', () => { - const types: SavedObjectsType[] = [ - { - name: 'typeA', - hidden: false, - namespaceType: 'agnostic', - mappings: { properties: {} }, - convertToAliasScript: 'some script', - }, - { - name: 'typeB', - hidden: true, - namespaceType: 'single', - indexPattern: 'myIndex', - mappings: { properties: {} }, - }, - { - name: 'typeC', - hidden: false, - namespaceType: 'multiple', - mappings: { properties: {} }, - }, - ]; - expect(convertTypesToLegacySchema(types)).toEqual({ - typeA: { - hidden: false, - isNamespaceAgnostic: true, - multiNamespace: false, - convertToAliasScript: 'some script', - }, - typeB: { - hidden: true, - isNamespaceAgnostic: false, - multiNamespace: false, - indexPattern: 'myIndex', - }, - typeC: { - hidden: false, - isNamespaceAgnostic: false, - multiNamespace: true, - }, - }); - }); -}); diff --git a/src/core/server/saved_objects/utils.ts b/src/core/server/saved_objects/utils.ts deleted file mode 100644 index af7c08d1fbfc..000000000000 --- a/src/core/server/saved_objects/utils.ts +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { LegacyConfig } from '../legacy'; -import { SavedObjectMigrationMap } from './migrations'; -import { - SavedObjectsNamespaceType, - SavedObjectsType, - SavedObjectsLegacyUiExports, - SavedObjectLegacyMigrationMap, - SavedObjectsLegacyManagementTypeDefinition, - SavedObjectsTypeManagementDefinition, -} from './types'; -import { SavedObjectsSchemaDefinition } from './schema'; - -/** - * Converts the legacy savedObjects mappings, schema, and migrations - * to actual {@link SavedObjectsType | saved object types} - */ -export const convertLegacyTypes = ( - { - savedObjectMappings = [], - savedObjectMigrations = {}, - savedObjectSchemas = {}, - savedObjectsManagement = {}, - }: SavedObjectsLegacyUiExports, - legacyConfig: LegacyConfig -): SavedObjectsType[] => { - return savedObjectMappings.reduce((types, { properties }) => { - return [ - ...types, - ...Object.entries(properties).map(([type, mappings]) => { - const schema = savedObjectSchemas[type]; - const migrations = savedObjectMigrations[type]; - const management = savedObjectsManagement[type]; - const namespaceType = (schema?.isNamespaceAgnostic - ? 'agnostic' - : schema?.multiNamespace - ? 'multiple' - : 'single') as SavedObjectsNamespaceType; - return { - name: type, - hidden: schema?.hidden ?? false, - namespaceType, - mappings, - indexPattern: - typeof schema?.indexPattern === 'function' - ? schema.indexPattern(legacyConfig) - : schema?.indexPattern, - convertToAliasScript: schema?.convertToAliasScript, - migrations: convertLegacyMigrations(migrations ?? {}), - management: management ? convertLegacyTypeManagement(management) : undefined, - }; - }), - ]; - }, [] as SavedObjectsType[]); -}; - -/** - * Convert {@link SavedObjectsType | saved object types} to the legacy {@link SavedObjectsSchemaDefinition | schema} format - */ -export const convertTypesToLegacySchema = ( - types: SavedObjectsType[] -): SavedObjectsSchemaDefinition => { - return types.reduce((schema, type) => { - return { - ...schema, - [type.name]: { - isNamespaceAgnostic: type.namespaceType === 'agnostic', - multiNamespace: type.namespaceType === 'multiple', - hidden: type.hidden, - indexPattern: type.indexPattern, - convertToAliasScript: type.convertToAliasScript, - }, - }; - }, {} as SavedObjectsSchemaDefinition); -}; - -const convertLegacyMigrations = ( - legacyMigrations: SavedObjectLegacyMigrationMap -): SavedObjectMigrationMap => { - return Object.entries(legacyMigrations).reduce((migrated, [version, migrationFn]) => { - return { - ...migrated, - [version]: (doc, context) => migrationFn(doc, context.log), - }; - }, {} as SavedObjectMigrationMap); -}; - -const convertLegacyTypeManagement = ( - legacyTypeManagement: SavedObjectsLegacyManagementTypeDefinition -): SavedObjectsTypeManagementDefinition => { - return { - importableAndExportable: legacyTypeManagement.isImportableAndExportable, - defaultSearchField: legacyTypeManagement.defaultSearchField, - icon: legacyTypeManagement.icon, - getTitle: legacyTypeManagement.getTitle, - getEditUrl: legacyTypeManagement.getEditUrl, - getInAppUrl: legacyTypeManagement.getInAppUrl, - }; -}; diff --git a/src/core/server/saved_objects/validation/index.ts b/src/core/server/saved_objects/validation/index.ts deleted file mode 100644 index b1b33f91d3fd..000000000000 --- a/src/core/server/saved_objects/validation/index.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* - * This is the core logic for validating saved object properties. The saved object client - * and migrations consume this in order to validate saved object documents prior to - * persisting them. - */ - -interface SavedObjectDoc { - type: string; - [prop: string]: any; -} - -/** - * A dictionary of property name -> validation function. The property name - * is generally the document's type (e.g. "dashboard"), but will also - * match other properties. - * - * For example, the "acl" and "dashboard" validators both apply to the - * following saved object: { type: "dashboard", attributes: {}, acl: "sdlaj3w" } - * - * @export - * @interface Validators - */ -export interface PropertyValidators { - [prop: string]: ValidateDoc; -} - -export type ValidateDoc = (doc: SavedObjectDoc) => void; - -/** - * Creates a function which uses a dictionary of property validators to validate - * individual saved object documents. - * - * @export - * @param {Validators} validators - * @param {SavedObjectDoc} doc - */ -export function docValidator(validators: PropertyValidators = {}): ValidateDoc { - return function validateDoc(doc: SavedObjectDoc) { - Object.keys(doc) - .concat(doc.type) - .forEach((prop) => { - const validator = validators[prop]; - if (validator) { - validator(doc); - } - }); - }; -} diff --git a/src/core/server/saved_objects/validation/readme.md b/src/core/server/saved_objects/validation/readme.md deleted file mode 100644 index 3b9f17c37fd0..000000000000 --- a/src/core/server/saved_objects/validation/readme.md +++ /dev/null @@ -1,63 +0,0 @@ -# Saved Object Validations - -The saved object client supports validation of documents during create / bulkCreate operations. - -This allows us tighter control over what documents get written to the saved object index, and helps us keep the index in a healthy state. - -## Creating validations - -Plugin authors can write their own validations by adding a `validations` property to their uiExports. A validation is nothing more than a dictionary of `{[prop: string]: validationFunction}` where: - -* `prop` - a root-property on a saved object document -* `validationFunction` - a function that takes a document and throws an error if it does not meet expectations. - -## Example - -```js -// In myFanciPlugin... -uiExports: { - validations: { - myProperty(doc) { - if (doc.attributes.someField === undefined) { - throw new Error(`Document ${doc.id} did not define "someField"`); - } - }, - - someOtherProp(doc) { - if (doc.attributes.counter < 0) { - throw new Error(`Document ${doc.id} cannot have a negative counter.`); - } - }, - }, -}, -``` - -In this example, `myFanciPlugin` defines validations for two properties: `myProperty` and `someOtherProp`. - -This means that no other plugin can define validations for myProperty or someOtherProp. - -The `myProperty` validation would run for any doc that has a `type="myProperty"` or for any doc that has a root-level property of `myProperty`. e.g. it would apply to all documents in the following array: - -```js -[ - { - type: 'foo', - attributes: { stuff: 'here' }, - myProperty: 'shazm!', - }, - { - type: 'myProperty', - attributes: { shazm: true }, - }, -]; -``` - -Validating properties other than just 'type' allows us to support potential future saved object scenarios in which plugins might want to annotate other plugin documents, such as a security plugin adding an acl to another document: - -```js -{ - type: 'dashboard', - attributes: { stuff: 'here' }, - acl: '342343', -} -``` diff --git a/src/core/server/saved_objects/validation/validation.test.ts b/src/core/server/saved_objects/validation/validation.test.ts deleted file mode 100644 index 71e220280ba5..000000000000 --- a/src/core/server/saved_objects/validation/validation.test.ts +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { docValidator } from './index'; - -describe('docValidator', () => { - test('does not run validators that have no application to the doc', () => { - const validators = { - foo: () => { - throw new Error('Boom!'); - }, - }; - expect(() => docValidator(validators)({ type: 'shoo', bar: 'hi' })).not.toThrow(); - }); - - test('validates the doc type', () => { - const validators = { - foo: () => { - throw new Error('Boom!'); - }, - }; - expect(() => docValidator(validators)({ type: 'foo' })).toThrow(/Boom!/); - }); - - test('validates various props', () => { - const validators = { - a: jest.fn(), - b: jest.fn(), - c: jest.fn(), - }; - docValidator(validators)({ type: 'a', b: 'foo' }); - - expect(validators.c).not.toHaveBeenCalled(); - - expect(validators.a.mock.calls).toEqual([[{ type: 'a', b: 'foo' }]]); - expect(validators.b.mock.calls).toEqual([[{ type: 'a', b: 'foo' }]]); - }); -}); diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 081554cd17f2..aef1bda9ccf4 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -1411,19 +1411,30 @@ export interface LegacyServiceStartDeps { plugins: Record; } -// Warning: (ae-forgotten-export) The symbol "SavedObjectsLegacyUiExports" needs to be exported by the entry point index.d.ts -// // @internal @deprecated (undocumented) -export type LegacyUiExports = SavedObjectsLegacyUiExports & { +export interface LegacyUiExports { + // Warning: (ae-forgotten-export) The symbol "VarsProvider" needs to be exported by the entry point index.d.ts + // + // (undocumented) defaultInjectedVarProviders?: VarsProvider[]; + // Warning: (ae-forgotten-export) The symbol "VarsReplacer" needs to be exported by the entry point index.d.ts + // + // (undocumented) injectedVarsReplacers?: VarsReplacer[]; + // Warning: (ae-forgotten-export) The symbol "LegacyNavLinkSpec" needs to be exported by the entry point index.d.ts + // + // (undocumented) navLinkSpecs?: LegacyNavLinkSpec[] | null; + // Warning: (ae-forgotten-export) The symbol "LegacyAppSpec" needs to be exported by the entry point index.d.ts + // + // (undocumented) uiAppSpecs?: Array; + // (undocumented) unknown?: [{ pluginSpec: LegacyPluginSpec; type: unknown; }]; -}; +} // Warning: (ae-forgotten-export) The symbol "lifecycleResponseFactory" needs to be exported by the entry point index.d.ts // @@ -1520,10 +1531,10 @@ export interface LogRecord { timestamp: Date; } -// Warning: (ae-missing-release-tag) "MetricsServiceSetup" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// -// @public (undocumented) +// @public export interface MetricsServiceSetup { + readonly collectionInterval: number; + getOpsMetrics$: () => Observable; } // @public @deprecated (undocumented) @@ -1610,6 +1621,7 @@ export interface OnPreRoutingToolkit { // @public export interface OpsMetrics { + collected_at: Date; concurrent_connections: OpsServerMetrics['concurrent_connections']; os: OpsOsMetrics; process: OpsProcessMetrics; @@ -1619,6 +1631,20 @@ export interface OpsMetrics { // @public export interface OpsOsMetrics { + cpu?: { + control_group: string; + cfs_period_micros: number; + cfs_quota_micros: number; + stat: { + number_of_elapsed_periods: number; + number_of_times_throttled: number; + time_throttled_nanos: number; + }; + }; + cpuacct?: { + control_group: string; + usage_nanos: number; + }; distro?: string; distroRelease?: string; load: { @@ -2437,33 +2463,6 @@ export interface SavedObjectsIncrementCounterOptions extends SavedObjectsBaseOpt refresh?: MutatingOperationRefreshSetting; } -// @internal @deprecated (undocumented) -export interface SavedObjectsLegacyService { - // Warning: (ae-forgotten-export) The symbol "SavedObjectsClientProvider" needs to be exported by the entry point index.d.ts - // - // (undocumented) - addScopedSavedObjectsClientWrapperFactory: SavedObjectsClientProvider['addClientWrapperFactory']; - // (undocumented) - getSavedObjectsRepository(...rest: any[]): any; - // (undocumented) - getScopedSavedObjectsClient: SavedObjectsClientProvider['getClient']; - // (undocumented) - importExport: { - objectLimit: number; - importSavedObjects(options: SavedObjectsImportOptions): Promise; - resolveImportErrors(options: SavedObjectsResolveImportErrorsOptions): Promise; - getSortedObjectsForExport(options: SavedObjectsExportOptions): Promise; - }; - // (undocumented) - SavedObjectsClient: typeof SavedObjectsClient; - // (undocumented) - schema: SavedObjectsSchema; - // (undocumented) - setScopedSavedObjectsClientFactory: SavedObjectsClientProvider['setClientFactory']; - // (undocumented) - types: string[]; -} - // @public export interface SavedObjectsMappingProperties { // (undocumented) @@ -2517,10 +2516,10 @@ export class SavedObjectsRepository { bulkUpdate(objects: Array>, options?: SavedObjectsBulkUpdateOptions): Promise>; checkConflicts(objects?: SavedObjectsCheckConflictsObject[], options?: SavedObjectsBaseOptions): Promise; create(type: string, attributes: T, options?: SavedObjectsCreateOptions): Promise>; - // Warning: (ae-forgotten-export) The symbol "KibanaMigrator" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "IKibanaMigrator" needs to be exported by the entry point index.d.ts // // @internal - static createRepository(migrator: KibanaMigrator, typeRegistry: SavedObjectTypeRegistry, indexName: string, client: ElasticsearchClient, includedHiddenTypes?: string[], injectedConstructor?: any): ISavedObjectsRepository; + static createRepository(migrator: IKibanaMigrator, typeRegistry: SavedObjectTypeRegistry, indexName: string, client: ElasticsearchClient, includedHiddenTypes?: string[], injectedConstructor?: any): ISavedObjectsRepository; delete(type: string, id: string, options?: SavedObjectsDeleteOptions): Promise<{}>; deleteByNamespace(namespace: string, options?: SavedObjectsDeleteByNamespaceOptions): Promise; deleteFromNamespaces(type: string, id: string, namespaces: string[], options?: SavedObjectsDeleteFromNamespacesOptions): Promise; @@ -2548,24 +2547,6 @@ export interface SavedObjectsResolveImportErrorsOptions { typeRegistry: ISavedObjectTypeRegistry; } -// @internal @deprecated (undocumented) -export class SavedObjectsSchema { - // Warning: (ae-forgotten-export) The symbol "SavedObjectsSchemaDefinition" needs to be exported by the entry point index.d.ts - constructor(schemaDefinition?: SavedObjectsSchemaDefinition); - // (undocumented) - getConvertToAliasScript(type: string): string | undefined; - // (undocumented) - getIndexForType(config: LegacyConfig, type: string): string | undefined; - // (undocumented) - isHiddenType(type: string): boolean; - // (undocumented) - isMultiNamespace(type: string): boolean; - // (undocumented) - isNamespaceAgnostic(type: string): boolean; - // (undocumented) - isSingleNamespace(type: string): boolean; -} - // @public export class SavedObjectsSerializer { // @internal @@ -2797,10 +2778,17 @@ export type SharedGlobalConfig = RecursiveReadonly<{ // @public export type StartServicesAccessor = () => Promise<[CoreStart, TPluginsStart, TStart]>; +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "ServiceStatusSetup" +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "ServiceStatusSetup" +// // @public export interface StatusServiceSetup { core$: Observable; + dependencies$: Observable>; + // Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "StatusSetup" + derivedStatus$: Observable; overall$: Observable; + set(status$: Observable): void; } // @public @@ -2888,13 +2876,9 @@ export const validBodyOutput: readonly ["data", "stream"]; // Warnings were encountered during analysis: // // src/core/server/http/router/response.ts:316:3 - (ae-forgotten-export) The symbol "KibanaResponse" needs to be exported by the entry point index.d.ts -// src/core/server/legacy/types.ts:132:3 - (ae-forgotten-export) The symbol "VarsProvider" needs to be exported by the entry point index.d.ts -// src/core/server/legacy/types.ts:133:3 - (ae-forgotten-export) The symbol "VarsReplacer" needs to be exported by the entry point index.d.ts -// src/core/server/legacy/types.ts:134:3 - (ae-forgotten-export) The symbol "LegacyNavLinkSpec" needs to be exported by the entry point index.d.ts -// src/core/server/legacy/types.ts:135:3 - (ae-forgotten-export) The symbol "LegacyAppSpec" needs to be exported by the entry point index.d.ts -// src/core/server/legacy/types.ts:136:16 - (ae-forgotten-export) The symbol "LegacyPluginSpec" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:266:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:266:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:268:3 - (ae-forgotten-export) The symbol "PathConfigType" needs to be exported by the entry point index.d.ts +// src/core/server/legacy/types.ts:135:16 - (ae-forgotten-export) The symbol "LegacyPluginSpec" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:272:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:272:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:274:3 - (ae-forgotten-export) The symbol "PathConfigType" needs to be exported by the entry point index.d.ts ``` diff --git a/src/core/server/server.test.ts b/src/core/server/server.test.ts index 417f66a2988c..8bf16d9130ef 100644 --- a/src/core/server/server.test.ts +++ b/src/core/server/server.test.ts @@ -49,7 +49,7 @@ const rawConfigService = rawConfigServiceMock.create({}); beforeEach(() => { mockConfigService.atPath.mockReturnValue(new BehaviorSubject({ autoListen: true })); mockPluginsService.discover.mockResolvedValue({ - pluginTree: new Map(), + pluginTree: { asOpaqueIds: new Map(), asNames: new Map() }, uiPlugins: { internal: new Map(), public: new Map(), browserConfigs: new Map() }, }); }); @@ -98,7 +98,7 @@ test('injects legacy dependency to context#setup()', async () => { [pluginB, [pluginA]], ]); mockPluginsService.discover.mockResolvedValue({ - pluginTree: pluginDependencies, + pluginTree: { asOpaqueIds: pluginDependencies, asNames: new Map() }, uiPlugins: { internal: new Map(), public: new Map(), browserConfigs: new Map() }, }); diff --git a/src/core/server/server.ts b/src/core/server/server.ts index cc6d8171e7a0..a02b0f51b559 100644 --- a/src/core/server/server.ts +++ b/src/core/server/server.ts @@ -121,10 +121,13 @@ export class Server { const contextServiceSetup = this.context.setup({ // We inject a fake "legacy plugin" with dependencies on every plugin so that legacy plugins: - // 1) Can access context from any NP plugin + // 1) Can access context from any KP plugin // 2) Can register context providers that will only be available to other legacy plugins and will not leak into // New Platform plugins. - pluginDependencies: new Map([...pluginTree, [this.legacy.legacyId, [...pluginTree.keys()]]]), + pluginDependencies: new Map([ + ...pluginTree.asOpaqueIds, + [this.legacy.legacyId, [...pluginTree.asOpaqueIds.keys()]], + ]), }); const auditTrailSetup = this.auditTrail.setup(); @@ -142,7 +145,6 @@ export class Server { const savedObjectsSetup = await this.savedObjects.setup({ http: httpSetup, elasticsearch: elasticsearchServiceSetup, - legacyPlugins, }); const uiSettingsSetup = await this.uiSettings.setup({ @@ -154,6 +156,7 @@ export class Server { const statusSetup = await this.status.setup({ elasticsearch: elasticsearchServiceSetup, + pluginDependencies: pluginTree.asNames, savedObjects: savedObjectsSetup, }); diff --git a/src/core/server/status/get_summary_status.test.ts b/src/core/server/status/get_summary_status.test.ts index 7516e82ee784..d97083162b50 100644 --- a/src/core/server/status/get_summary_status.test.ts +++ b/src/core/server/status/get_summary_status.test.ts @@ -94,6 +94,38 @@ describe('getSummaryStatus', () => { describe('summary', () => { describe('when a single service is at highest level', () => { it('returns all information about that single service', () => { + expect( + getSummaryStatus( + Object.entries({ + s1: degraded, + s2: { + level: ServiceStatusLevels.unavailable, + summary: 'Lorem ipsum', + meta: { + custom: { data: 'here' }, + }, + }, + }) + ) + ).toEqual({ + level: ServiceStatusLevels.unavailable, + summary: '[s2]: Lorem ipsum', + detail: 'See the status page for more information', + meta: { + affectedServices: { + s2: { + level: ServiceStatusLevels.unavailable, + summary: 'Lorem ipsum', + meta: { + custom: { data: 'here' }, + }, + }, + }, + }, + }); + }); + + it('allows the single service to override the detail and documentationUrl fields', () => { expect( getSummaryStatus( Object.entries({ @@ -115,7 +147,17 @@ describe('getSummaryStatus', () => { detail: 'Vivamus pulvinar sem ac luctus ultrices.', documentationUrl: 'http://helpmenow.com/problem1', meta: { - custom: { data: 'here' }, + affectedServices: { + s2: { + level: ServiceStatusLevels.unavailable, + summary: 'Lorem ipsum', + detail: 'Vivamus pulvinar sem ac luctus ultrices.', + documentationUrl: 'http://helpmenow.com/problem1', + meta: { + custom: { data: 'here' }, + }, + }, + }, }, }); }); diff --git a/src/core/server/status/get_summary_status.ts b/src/core/server/status/get_summary_status.ts index 748a54f0bf8b..8d97cdbd9b15 100644 --- a/src/core/server/status/get_summary_status.ts +++ b/src/core/server/status/get_summary_status.ts @@ -23,62 +23,60 @@ import { ServiceStatus, ServiceStatusLevels, ServiceStatusLevel } from './types' * Returns a single {@link ServiceStatus} that summarizes the most severe status level from a group of statuses. * @param statuses */ -export const getSummaryStatus = (statuses: Array<[string, ServiceStatus]>): ServiceStatus => { - const grouped = groupByLevel(statuses); - const highestSeverityLevel = getHighestSeverityLevel(grouped.keys()); - const highestSeverityGroup = grouped.get(highestSeverityLevel)!; +export const getSummaryStatus = ( + statuses: Array<[string, ServiceStatus]>, + { allAvailableSummary = `All services are available` }: { allAvailableSummary?: string } = {} +): ServiceStatus => { + const { highestLevel, highestStatuses } = highestLevelSummary(statuses); - if (highestSeverityLevel === ServiceStatusLevels.available) { + if (highestLevel === ServiceStatusLevels.available) { return { level: ServiceStatusLevels.available, - summary: `All services are available`, + summary: allAvailableSummary, }; - } else if (highestSeverityGroup.size === 1) { - const [serviceName, status] = [...highestSeverityGroup.entries()][0]; + } else if (highestStatuses.length === 1) { + const [serviceName, status] = highestStatuses[0]! as [string, ServiceStatus]; return { ...status, summary: `[${serviceName}]: ${status.summary!}`, + // TODO: include URL to status page + detail: status.detail ?? `See the status page for more information`, + meta: { + affectedServices: { [serviceName]: status }, + }, }; } else { return { - level: highestSeverityLevel, - summary: `[${highestSeverityGroup.size}] services are ${highestSeverityLevel.toString()}`, + level: highestLevel, + summary: `[${highestStatuses.length}] services are ${highestLevel.toString()}`, // TODO: include URL to status page detail: `See the status page for more information`, meta: { - affectedServices: Object.fromEntries([...highestSeverityGroup]), + affectedServices: Object.fromEntries(highestStatuses), }, }; } }; -const groupByLevel = ( - statuses: Array<[string, ServiceStatus]> -): Map> => { - const byLevel = new Map>(); +type StatusPair = [string, ServiceStatus]; - for (const [serviceName, status] of statuses) { - let levelMap = byLevel.get(status.level); - if (!levelMap) { - levelMap = new Map(); - byLevel.set(status.level, levelMap); - } +const highestLevelSummary = ( + statuses: StatusPair[] +): { highestLevel: ServiceStatusLevel; highestStatuses: StatusPair[] } => { + let highestLevel: ServiceStatusLevel = ServiceStatusLevels.available; + let highestStatuses: StatusPair[] = []; - levelMap.set(serviceName, status); + for (const pair of statuses) { + if (pair[1].level === highestLevel) { + highestStatuses.push(pair); + } else if (pair[1].level > highestLevel) { + highestLevel = pair[1].level; + highestStatuses = [pair]; + } } - return byLevel; -}; - -const getHighestSeverityLevel = (levels: Iterable): ServiceStatusLevel => { - const sorted = [...levels].sort((a, b) => { - if (a < b) { - return -1; - } else if (a > b) { - return 1; - } else { - return 0; - } - }); - return sorted[sorted.length - 1] ?? ServiceStatusLevels.available; + return { + highestLevel, + highestStatuses, + }; }; diff --git a/src/core/server/status/plugins_status.test.ts b/src/core/server/status/plugins_status.test.ts new file mode 100644 index 000000000000..a75dc8c28369 --- /dev/null +++ b/src/core/server/status/plugins_status.test.ts @@ -0,0 +1,338 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { PluginName } from '../plugins'; +import { PluginsStatusService } from './plugins_status'; +import { of, Observable, BehaviorSubject } from 'rxjs'; +import { ServiceStatusLevels, CoreStatus, ServiceStatus } from './types'; +import { first } from 'rxjs/operators'; +import { ServiceStatusLevelSnapshotSerializer } from './test_utils'; + +expect.addSnapshotSerializer(ServiceStatusLevelSnapshotSerializer); + +describe('PluginStatusService', () => { + const coreAllAvailable$: Observable = of({ + elasticsearch: { level: ServiceStatusLevels.available, summary: 'elasticsearch avail' }, + savedObjects: { level: ServiceStatusLevels.available, summary: 'savedObjects avail' }, + }); + const coreOneDegraded$: Observable = of({ + elasticsearch: { level: ServiceStatusLevels.available, summary: 'elasticsearch avail' }, + savedObjects: { level: ServiceStatusLevels.degraded, summary: 'savedObjects degraded' }, + }); + const coreOneCriticalOneDegraded$: Observable = of({ + elasticsearch: { level: ServiceStatusLevels.critical, summary: 'elasticsearch critical' }, + savedObjects: { level: ServiceStatusLevels.degraded, summary: 'savedObjects degraded' }, + }); + const pluginDependencies: Map = new Map([ + ['a', []], + ['b', ['a']], + ['c', ['a', 'b']], + ]); + + describe('getDerivedStatus$', () => { + it(`defaults to core's most severe status`, async () => { + const serviceAvailable = new PluginsStatusService({ + core$: coreAllAvailable$, + pluginDependencies, + }); + expect(await serviceAvailable.getDerivedStatus$('a').pipe(first()).toPromise()).toEqual({ + level: ServiceStatusLevels.available, + summary: 'All dependencies are available', + }); + + const serviceDegraded = new PluginsStatusService({ + core$: coreOneDegraded$, + pluginDependencies, + }); + expect(await serviceDegraded.getDerivedStatus$('a').pipe(first()).toPromise()).toEqual({ + level: ServiceStatusLevels.degraded, + summary: '[savedObjects]: savedObjects degraded', + detail: 'See the status page for more information', + meta: expect.any(Object), + }); + + const serviceCritical = new PluginsStatusService({ + core$: coreOneCriticalOneDegraded$, + pluginDependencies, + }); + expect(await serviceCritical.getDerivedStatus$('a').pipe(first()).toPromise()).toEqual({ + level: ServiceStatusLevels.critical, + summary: '[elasticsearch]: elasticsearch critical', + detail: 'See the status page for more information', + meta: expect.any(Object), + }); + }); + + it(`provides a summary status when core and dependencies are at same severity level`, async () => { + const service = new PluginsStatusService({ core$: coreOneDegraded$, pluginDependencies }); + service.set('a', of({ level: ServiceStatusLevels.degraded, summary: 'a is degraded' })); + expect(await service.getDerivedStatus$('b').pipe(first()).toPromise()).toEqual({ + level: ServiceStatusLevels.degraded, + summary: '[2] services are degraded', + detail: 'See the status page for more information', + meta: expect.any(Object), + }); + }); + + it(`allows dependencies status to take precedence over lower severity core statuses`, async () => { + const service = new PluginsStatusService({ core$: coreOneDegraded$, pluginDependencies }); + service.set('a', of({ level: ServiceStatusLevels.unavailable, summary: 'a is not working' })); + expect(await service.getDerivedStatus$('b').pipe(first()).toPromise()).toEqual({ + level: ServiceStatusLevels.unavailable, + summary: '[a]: a is not working', + detail: 'See the status page for more information', + meta: expect.any(Object), + }); + }); + + it(`allows core status to take precedence over lower severity dependencies statuses`, async () => { + const service = new PluginsStatusService({ + core$: coreOneCriticalOneDegraded$, + pluginDependencies, + }); + service.set('a', of({ level: ServiceStatusLevels.unavailable, summary: 'a is not working' })); + expect(await service.getDerivedStatus$('b').pipe(first()).toPromise()).toEqual({ + level: ServiceStatusLevels.critical, + summary: '[elasticsearch]: elasticsearch critical', + detail: 'See the status page for more information', + meta: expect.any(Object), + }); + }); + + it(`allows a severe dependency status to take precedence over a less severe dependency status`, async () => { + const service = new PluginsStatusService({ core$: coreOneDegraded$, pluginDependencies }); + service.set('a', of({ level: ServiceStatusLevels.degraded, summary: 'a is degraded' })); + service.set('b', of({ level: ServiceStatusLevels.unavailable, summary: 'b is not working' })); + expect(await service.getDerivedStatus$('c').pipe(first()).toPromise()).toEqual({ + level: ServiceStatusLevels.unavailable, + summary: '[b]: b is not working', + detail: 'See the status page for more information', + meta: expect.any(Object), + }); + }); + }); + + describe('getAll$', () => { + it('defaults to empty record if no plugins', async () => { + const service = new PluginsStatusService({ + core$: coreAllAvailable$, + pluginDependencies: new Map(), + }); + expect(await service.getAll$().pipe(first()).toPromise()).toEqual({}); + }); + + it('defaults to core status when no plugin statuses are set', async () => { + const serviceAvailable = new PluginsStatusService({ + core$: coreAllAvailable$, + pluginDependencies, + }); + expect(await serviceAvailable.getAll$().pipe(first()).toPromise()).toEqual({ + a: { level: ServiceStatusLevels.available, summary: 'All dependencies are available' }, + b: { level: ServiceStatusLevels.available, summary: 'All dependencies are available' }, + c: { level: ServiceStatusLevels.available, summary: 'All dependencies are available' }, + }); + + const serviceDegraded = new PluginsStatusService({ + core$: coreOneDegraded$, + pluginDependencies, + }); + expect(await serviceDegraded.getAll$().pipe(first()).toPromise()).toEqual({ + a: { + level: ServiceStatusLevels.degraded, + summary: '[savedObjects]: savedObjects degraded', + detail: 'See the status page for more information', + meta: expect.any(Object), + }, + b: { + level: ServiceStatusLevels.degraded, + summary: '[2] services are degraded', + detail: 'See the status page for more information', + meta: expect.any(Object), + }, + c: { + level: ServiceStatusLevels.degraded, + summary: '[3] services are degraded', + detail: 'See the status page for more information', + meta: expect.any(Object), + }, + }); + + const serviceCritical = new PluginsStatusService({ + core$: coreOneCriticalOneDegraded$, + pluginDependencies, + }); + expect(await serviceCritical.getAll$().pipe(first()).toPromise()).toEqual({ + a: { + level: ServiceStatusLevels.critical, + summary: '[elasticsearch]: elasticsearch critical', + detail: 'See the status page for more information', + meta: expect.any(Object), + }, + b: { + level: ServiceStatusLevels.critical, + summary: '[2] services are critical', + detail: 'See the status page for more information', + meta: expect.any(Object), + }, + c: { + level: ServiceStatusLevels.critical, + summary: '[3] services are critical', + detail: 'See the status page for more information', + meta: expect.any(Object), + }, + }); + }); + + it('uses the manually set status level if plugin specifies one', async () => { + const service = new PluginsStatusService({ core$: coreOneDegraded$, pluginDependencies }); + service.set('a', of({ level: ServiceStatusLevels.available, summary: 'a status' })); + + expect(await service.getAll$().pipe(first()).toPromise()).toEqual({ + a: { level: ServiceStatusLevels.available, summary: 'a status' }, // a is available depsite savedObjects being degraded + b: { + level: ServiceStatusLevels.degraded, + summary: '[savedObjects]: savedObjects degraded', + detail: 'See the status page for more information', + meta: expect.any(Object), + }, + c: { + level: ServiceStatusLevels.degraded, + summary: '[2] services are degraded', + detail: 'See the status page for more information', + meta: expect.any(Object), + }, + }); + }); + + it('updates when a new plugin status observable is set', async () => { + const service = new PluginsStatusService({ + core$: coreAllAvailable$, + pluginDependencies: new Map([['a', []]]), + }); + const statusUpdates: Array> = []; + const subscription = service + .getAll$() + .subscribe((pluginStatuses) => statusUpdates.push(pluginStatuses)); + + service.set('a', of({ level: ServiceStatusLevels.degraded, summary: 'a degraded' })); + service.set('a', of({ level: ServiceStatusLevels.unavailable, summary: 'a unavailable' })); + service.set('a', of({ level: ServiceStatusLevels.available, summary: 'a available' })); + subscription.unsubscribe(); + + expect(statusUpdates).toEqual([ + { a: { level: ServiceStatusLevels.available, summary: 'All dependencies are available' } }, + { a: { level: ServiceStatusLevels.degraded, summary: 'a degraded' } }, + { a: { level: ServiceStatusLevels.unavailable, summary: 'a unavailable' } }, + { a: { level: ServiceStatusLevels.available, summary: 'a available' } }, + ]); + }); + }); + + describe('getDependenciesStatus$', () => { + it('only includes dependencies of specified plugin', async () => { + const service = new PluginsStatusService({ + core$: coreAllAvailable$, + pluginDependencies, + }); + expect(await service.getDependenciesStatus$('a').pipe(first()).toPromise()).toEqual({}); + expect(await service.getDependenciesStatus$('b').pipe(first()).toPromise()).toEqual({ + a: { level: ServiceStatusLevels.available, summary: 'All dependencies are available' }, + }); + expect(await service.getDependenciesStatus$('c').pipe(first()).toPromise()).toEqual({ + a: { level: ServiceStatusLevels.available, summary: 'All dependencies are available' }, + b: { level: ServiceStatusLevels.available, summary: 'All dependencies are available' }, + }); + }); + + it('uses the manually set status level if plugin specifies one', async () => { + const service = new PluginsStatusService({ core$: coreOneDegraded$, pluginDependencies }); + service.set('a', of({ level: ServiceStatusLevels.available, summary: 'a status' })); + + expect(await service.getDependenciesStatus$('c').pipe(first()).toPromise()).toEqual({ + a: { level: ServiceStatusLevels.available, summary: 'a status' }, // a is available depsite savedObjects being degraded + b: { + level: ServiceStatusLevels.degraded, + summary: '[savedObjects]: savedObjects degraded', + detail: 'See the status page for more information', + meta: expect.any(Object), + }, + }); + }); + + it('throws error if unknown plugin passed', () => { + const service = new PluginsStatusService({ core$: coreAllAvailable$, pluginDependencies }); + expect(() => { + service.getDependenciesStatus$('dont-exist'); + }).toThrowError(); + }); + + it('debounces events in quick succession', async () => { + const service = new PluginsStatusService({ + core$: coreAllAvailable$, + pluginDependencies, + }); + const available: ServiceStatus = { + level: ServiceStatusLevels.available, + summary: 'a available', + }; + const degraded: ServiceStatus = { + level: ServiceStatusLevels.degraded, + summary: 'a degraded', + }; + const pluginA$ = new BehaviorSubject(available); + service.set('a', pluginA$); + + const statusUpdates: Array> = []; + const subscription = service + .getDependenciesStatus$('b') + .subscribe((status) => statusUpdates.push(status)); + const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + + pluginA$.next(degraded); + pluginA$.next(available); + pluginA$.next(degraded); + pluginA$.next(available); + pluginA$.next(degraded); + pluginA$.next(available); + pluginA$.next(degraded); + // Waiting for the debounce timeout should cut a new update + await delay(500); + pluginA$.next(available); + await delay(500); + subscription.unsubscribe(); + + expect(statusUpdates).toMatchInlineSnapshot(` + Array [ + Object { + "a": Object { + "level": degraded, + "summary": "a degraded", + }, + }, + Object { + "a": Object { + "level": available, + "summary": "a available", + }, + }, + ] + `); + }); + }); +}); diff --git a/src/core/server/status/plugins_status.ts b/src/core/server/status/plugins_status.ts new file mode 100644 index 000000000000..113d59b327c1 --- /dev/null +++ b/src/core/server/status/plugins_status.ts @@ -0,0 +1,98 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { BehaviorSubject, Observable, combineLatest, of } from 'rxjs'; +import { map, distinctUntilChanged, switchMap, debounceTime } from 'rxjs/operators'; +import { isDeepStrictEqual } from 'util'; + +import { PluginName } from '../plugins'; +import { ServiceStatus, CoreStatus } from './types'; +import { getSummaryStatus } from './get_summary_status'; + +interface Deps { + core$: Observable; + pluginDependencies: ReadonlyMap; +} + +export class PluginsStatusService { + private readonly pluginStatuses = new Map>(); + private readonly update$ = new BehaviorSubject(true); + constructor(private readonly deps: Deps) {} + + public set(plugin: PluginName, status$: Observable) { + this.pluginStatuses.set(plugin, status$); + this.update$.next(true); // trigger all existing Observables to update from the new source Observable + } + + public getAll$(): Observable> { + return this.getPluginStatuses$([...this.deps.pluginDependencies.keys()]); + } + + public getDependenciesStatus$(plugin: PluginName): Observable> { + const dependencies = this.deps.pluginDependencies.get(plugin); + if (!dependencies) { + throw new Error(`Unknown plugin: ${plugin}`); + } + + return this.getPluginStatuses$(dependencies).pipe( + // Prevent many emissions at once from dependency status resolution from making this too noisy + debounceTime(500) + ); + } + + public getDerivedStatus$(plugin: PluginName): Observable { + return combineLatest([this.deps.core$, this.getDependenciesStatus$(plugin)]).pipe( + map(([coreStatus, pluginStatuses]) => { + return getSummaryStatus( + [...Object.entries(coreStatus), ...Object.entries(pluginStatuses)], + { + allAvailableSummary: `All dependencies are available`, + } + ); + }) + ); + } + + private getPluginStatuses$(plugins: PluginName[]): Observable> { + if (plugins.length === 0) { + return of({}); + } + + return this.update$.pipe( + switchMap(() => { + const pluginStatuses = plugins + .map( + (depName) => + [depName, this.pluginStatuses.get(depName) ?? this.getDerivedStatus$(depName)] as [ + PluginName, + Observable + ] + ) + .map(([pName, status$]) => + status$.pipe(map((status) => [pName, status] as [PluginName, ServiceStatus])) + ); + + return combineLatest(pluginStatuses).pipe( + map((statuses) => Object.fromEntries(statuses)), + distinctUntilChanged(isDeepStrictEqual) + ); + }) + ); + } +} diff --git a/src/core/server/status/status_service.mock.ts b/src/core/server/status/status_service.mock.ts index 47ef8659b407..42b3eecdca31 100644 --- a/src/core/server/status/status_service.mock.ts +++ b/src/core/server/status/status_service.mock.ts @@ -40,6 +40,9 @@ const createSetupContractMock = () => { const setupContract: jest.Mocked = { core$: new BehaviorSubject(availableCoreStatus), overall$: new BehaviorSubject(available), + set: jest.fn(), + dependencies$: new BehaviorSubject({}), + derivedStatus$: new BehaviorSubject(available), }; return setupContract; @@ -50,6 +53,11 @@ const createInternalSetupContractMock = () => { core$: new BehaviorSubject(availableCoreStatus), overall$: new BehaviorSubject(available), isStatusPageAnonymous: jest.fn().mockReturnValue(false), + plugins: { + set: jest.fn(), + getDependenciesStatus$: jest.fn(), + getDerivedStatus$: jest.fn(), + }, }; return setupContract; diff --git a/src/core/server/status/status_service.test.ts b/src/core/server/status/status_service.test.ts index 863fe34e8ece..dcb1e0a559f5 100644 --- a/src/core/server/status/status_service.test.ts +++ b/src/core/server/status/status_service.test.ts @@ -34,6 +34,7 @@ describe('StatusService', () => { service = new StatusService(mockCoreContext.create()); }); + const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const available: ServiceStatus = { level: ServiceStatusLevels.available, summary: 'Available', @@ -53,6 +54,7 @@ describe('StatusService', () => { savedObjects: { status$: of(degraded), }, + pluginDependencies: new Map(), }); expect(await setup.core$.pipe(first()).toPromise()).toEqual({ elasticsearch: available, @@ -68,6 +70,7 @@ describe('StatusService', () => { savedObjects: { status$: of(degraded), }, + pluginDependencies: new Map(), }); const subResult1 = await setup.core$.pipe(first()).toPromise(); const subResult2 = await setup.core$.pipe(first()).toPromise(); @@ -96,6 +99,7 @@ describe('StatusService', () => { savedObjects: { status$: savedObjects$, }, + pluginDependencies: new Map(), }); const statusUpdates: CoreStatus[] = []; @@ -158,6 +162,7 @@ describe('StatusService', () => { savedObjects: { status$: of(degraded), }, + pluginDependencies: new Map(), }); expect(await setup.overall$.pipe(first()).toPromise()).toMatchObject({ level: ServiceStatusLevels.degraded, @@ -173,6 +178,7 @@ describe('StatusService', () => { savedObjects: { status$: of(degraded), }, + pluginDependencies: new Map(), }); const subResult1 = await setup.overall$.pipe(first()).toPromise(); const subResult2 = await setup.overall$.pipe(first()).toPromise(); @@ -201,26 +207,95 @@ describe('StatusService', () => { savedObjects: { status$: savedObjects$, }, + pluginDependencies: new Map(), }); const statusUpdates: ServiceStatus[] = []; const subscription = setup.overall$.subscribe((status) => statusUpdates.push(status)); + // Wait for timers to ensure that duplicate events are still filtered out regardless of debouncing. elasticsearch$.next(available); + await delay(500); elasticsearch$.next(available); + await delay(500); elasticsearch$.next({ level: ServiceStatusLevels.available, summary: `Wow another summary`, }); + await delay(500); savedObjects$.next(degraded); + await delay(500); savedObjects$.next(available); + await delay(500); savedObjects$.next(available); + await delay(500); subscription.unsubscribe(); expect(statusUpdates).toMatchInlineSnapshot(` Array [ Object { + "detail": "See the status page for more information", "level": degraded, + "meta": Object { + "affectedServices": Object { + "savedObjects": Object { + "level": degraded, + "summary": "This is degraded!", + }, + }, + }, + "summary": "[savedObjects]: This is degraded!", + }, + Object { + "level": available, + "summary": "All services are available", + }, + ] + `); + }); + + it('debounces events in quick succession', async () => { + const savedObjects$ = new BehaviorSubject(available); + const setup = await service.setup({ + elasticsearch: { + status$: new BehaviorSubject(available), + }, + savedObjects: { + status$: savedObjects$, + }, + pluginDependencies: new Map(), + }); + + const statusUpdates: ServiceStatus[] = []; + const subscription = setup.overall$.subscribe((status) => statusUpdates.push(status)); + + // All of these should debounced into a single `available` status + savedObjects$.next(degraded); + savedObjects$.next(available); + savedObjects$.next(degraded); + savedObjects$.next(available); + savedObjects$.next(degraded); + savedObjects$.next(available); + savedObjects$.next(degraded); + // Waiting for the debounce timeout should cut a new update + await delay(500); + savedObjects$.next(available); + await delay(500); + subscription.unsubscribe(); + + expect(statusUpdates).toMatchInlineSnapshot(` + Array [ + Object { + "detail": "See the status page for more information", + "level": degraded, + "meta": Object { + "affectedServices": Object { + "savedObjects": Object { + "level": degraded, + "summary": "This is degraded!", + }, + }, + }, "summary": "[savedObjects]: This is degraded!", }, Object { diff --git a/src/core/server/status/status_service.ts b/src/core/server/status/status_service.ts index aea335e64bab..8fe65eddb61d 100644 --- a/src/core/server/status/status_service.ts +++ b/src/core/server/status/status_service.ts @@ -18,7 +18,7 @@ */ import { Observable, combineLatest } from 'rxjs'; -import { map, distinctUntilChanged, shareReplay, take } from 'rxjs/operators'; +import { map, distinctUntilChanged, shareReplay, take, debounceTime } from 'rxjs/operators'; import { isDeepStrictEqual } from 'util'; import { CoreService } from '../../types'; @@ -26,13 +26,16 @@ import { CoreContext } from '../core_context'; import { Logger } from '../logging'; import { InternalElasticsearchServiceSetup } from '../elasticsearch'; import { InternalSavedObjectsServiceSetup } from '../saved_objects'; +import { PluginName } from '../plugins'; import { config, StatusConfigType } from './status_config'; import { ServiceStatus, CoreStatus, InternalStatusServiceSetup } from './types'; import { getSummaryStatus } from './get_summary_status'; +import { PluginsStatusService } from './plugins_status'; interface SetupDeps { elasticsearch: Pick; + pluginDependencies: ReadonlyMap; savedObjects: Pick; } @@ -40,26 +43,44 @@ export class StatusService implements CoreService { private readonly logger: Logger; private readonly config$: Observable; + private pluginsStatus?: PluginsStatusService; + constructor(coreContext: CoreContext) { this.logger = coreContext.logger.get('status'); this.config$ = coreContext.configService.atPath(config.path); } - public async setup(core: SetupDeps) { + public async setup({ elasticsearch, pluginDependencies, savedObjects }: SetupDeps) { const statusConfig = await this.config$.pipe(take(1)).toPromise(); - const core$ = this.setupCoreStatus(core); - const overall$: Observable = core$.pipe( - map((coreStatus) => { - const summary = getSummaryStatus(Object.entries(coreStatus)); + const core$ = this.setupCoreStatus({ elasticsearch, savedObjects }); + this.pluginsStatus = new PluginsStatusService({ core$, pluginDependencies }); + + const overall$: Observable = combineLatest( + core$, + this.pluginsStatus.getAll$() + ).pipe( + // Prevent many emissions at once from dependency status resolution from making this too noisy + debounceTime(500), + map(([coreStatus, pluginsStatus]) => { + const summary = getSummaryStatus([ + ...Object.entries(coreStatus), + ...Object.entries(pluginsStatus), + ]); this.logger.debug(`Recalculated overall status`, { status: summary }); return summary; }), - distinctUntilChanged(isDeepStrictEqual) + distinctUntilChanged(isDeepStrictEqual), + shareReplay(1) ); return { core$, overall$, + plugins: { + set: this.pluginsStatus.set.bind(this.pluginsStatus), + getDependenciesStatus$: this.pluginsStatus.getDependenciesStatus$.bind(this.pluginsStatus), + getDerivedStatus$: this.pluginsStatus.getDerivedStatus$.bind(this.pluginsStatus), + }, isStatusPageAnonymous: () => statusConfig.allowAnonymous, }; } @@ -68,7 +89,10 @@ export class StatusService implements CoreService { public stop() {} - private setupCoreStatus({ elasticsearch, savedObjects }: SetupDeps): Observable { + private setupCoreStatus({ + elasticsearch, + savedObjects, + }: Pick): Observable { return combineLatest([elasticsearch.status$, savedObjects.status$]).pipe( map(([elasticsearchStatus, savedObjectsStatus]) => ({ elasticsearch: elasticsearchStatus, diff --git a/src/core/server/status/types.ts b/src/core/server/status/types.ts index 2ecf11deb296..f884b80316fa 100644 --- a/src/core/server/status/types.ts +++ b/src/core/server/status/types.ts @@ -19,6 +19,7 @@ import { Observable } from 'rxjs'; import { deepFreeze } from '../../utils'; +import { PluginName } from '../plugins'; /** * The current status of a service at a point in time. @@ -116,6 +117,60 @@ export interface CoreStatus { /** * API for accessing status of Core and this plugin's dependencies as well as for customizing this plugin's status. + * + * @remarks + * By default, a plugin inherits it's current status from the most severe status level of any Core services and any + * plugins that it depends on. This default status is available on the + * {@link ServiceStatusSetup.derivedStatus$ | core.status.derviedStatus$} API. + * + * Plugins may customize their status calculation by calling the {@link ServiceStatusSetup.set | core.status.set} API + * with an Observable. Within this Observable, a plugin may choose to only depend on the status of some of its + * dependencies, to ignore severe status levels of particular Core services they are not concerned with, or to make its + * status dependent on other external services. + * + * @example + * Customize a plugin's status to only depend on the status of SavedObjects: + * ```ts + * core.status.set( + * core.status.core$.pipe( + * . map((coreStatus) => { + * return coreStatus.savedObjects; + * }) ; + * ); + * ); + * ``` + * + * @example + * Customize a plugin's status to include an external service: + * ```ts + * const externalStatus$ = interval(1000).pipe( + * switchMap(async () => { + * const resp = await fetch(`https://myexternaldep.com/_healthz`); + * const body = await resp.json(); + * if (body.ok) { + * return of({ level: ServiceStatusLevels.available, summary: 'External Service is up'}); + * } else { + * return of({ level: ServiceStatusLevels.available, summary: 'External Service is unavailable'}); + * } + * }), + * catchError((error) => { + * of({ level: ServiceStatusLevels.unavailable, summary: `External Service is down`, meta: { error }}) + * }) + * ); + * + * core.status.set( + * combineLatest([core.status.derivedStatus$, externalStatus$]).pipe( + * map(([derivedStatus, externalStatus]) => { + * if (externalStatus.level > derivedStatus) { + * return externalStatus; + * } else { + * return derivedStatus; + * } + * }) + * ) + * ); + * ``` + * * @public */ export interface StatusServiceSetup { @@ -134,9 +189,43 @@ export interface StatusServiceSetup { * only depend on the statuses of {@link StatusServiceSetup.core$ | Core} or their dependencies. */ overall$: Observable; + + /** + * Allows a plugin to specify a custom status dependent on its own criteria. + * Completely overrides the default inherited status. + * + * @remarks + * See the {@link StatusServiceSetup.derivedStatus$} API for leveraging the default status + * calculation that is provided by Core. + */ + set(status$: Observable): void; + + /** + * Current status for all plugins this plugin depends on. + * Each key of the `Record` is a plugin id. + */ + dependencies$: Observable>; + + /** + * The status of this plugin as derived from its dependencies. + * + * @remarks + * By default, plugins inherit this derived status from their dependencies. + * Calling {@link StatusSetup.set} overrides this default status. + * + * This may emit multliple times for a single status change event as propagates + * through the dependency tree + */ + derivedStatus$: Observable; } /** @internal */ -export interface InternalStatusServiceSetup extends StatusServiceSetup { +export interface InternalStatusServiceSetup extends Pick { isStatusPageAnonymous: () => boolean; + // Namespaced under `plugins` key to improve clarity that these are APIs for plugins specifically. + plugins: { + set(plugin: PluginName, status$: Observable): void; + getDependenciesStatus$(plugin: PluginName): Observable>; + getDerivedStatus$(plugin: PluginName): Observable; + }; } diff --git a/src/core/server/ui_settings/create_or_upgrade_saved_config/integration_tests/create_or_upgrade.test.ts b/src/core/server/ui_settings/create_or_upgrade_saved_config/integration_tests/create_or_upgrade.test.ts index 61b71f8c5de0..c7d5413ecca5 100644 --- a/src/core/server/ui_settings/create_or_upgrade_saved_config/integration_tests/create_or_upgrade.test.ts +++ b/src/core/server/ui_settings/create_or_upgrade_saved_config/integration_tests/create_or_upgrade.test.ts @@ -36,8 +36,6 @@ describe('createOrUpgradeSavedConfig()', () => { let esServer: TestElasticsearchUtils; let kbn: TestKibanaUtils; - let kbnServer: TestKibanaUtils['kbnServer']; - beforeAll(async function () { servers = createTestServers({ adjustTimeout: (t) => { @@ -46,10 +44,8 @@ describe('createOrUpgradeSavedConfig()', () => { }); esServer = await servers.startES(); kbn = await servers.startKibana(); - kbnServer = kbn.kbnServer; - const savedObjects = kbnServer.server.savedObjects; - savedObjectsClient = savedObjects.getScopedSavedObjectsClient( + savedObjectsClient = kbn.coreStart.savedObjects.getScopedClient( httpServerMock.createKibanaRequest() ); diff --git a/src/core/server/ui_settings/integration_tests/lib/servers.ts b/src/core/server/ui_settings/integration_tests/lib/servers.ts index 297deb0233c5..0bdc821f4258 100644 --- a/src/core/server/ui_settings/integration_tests/lib/servers.ts +++ b/src/core/server/ui_settings/integration_tests/lib/servers.ts @@ -68,8 +68,7 @@ export function getServices() { const callCluster = esServer.es.getCallCluster(); - const savedObjects = kbnServer.server.savedObjects; - const savedObjectsClient = savedObjects.getScopedSavedObjectsClient( + const savedObjectsClient = kbn.coreStart.savedObjects.getScopedClient( httpServerMock.createKibanaRequest() ); diff --git a/src/core/test_helpers/kbn_server.ts b/src/core/test_helpers/kbn_server.ts index a494c6aa31d6..488c4b919d3e 100644 --- a/src/core/test_helpers/kbn_server.ts +++ b/src/core/test_helpers/kbn_server.ts @@ -32,6 +32,7 @@ import { resolve } from 'path'; import { BehaviorSubject } from 'rxjs'; import supertest from 'supertest'; +import { CoreStart } from 'src/core/server'; import { LegacyAPICaller } from '../server/elasticsearch'; import { CliArgs, Env } from '../server/config'; import { Root } from '../server/root'; @@ -170,6 +171,7 @@ export interface TestElasticsearchUtils { export interface TestKibanaUtils { root: Root; + coreStart: CoreStart; kbnServer: KbnServer; stop: () => Promise; } @@ -289,13 +291,14 @@ export function createTestServers({ const root = createRootWithCorePlugins(kbnSettings); await root.setup(); - await root.start(); + const coreStart = await root.start(); const kbnServer = getKbnServer(root); return { root, kbnServer, + coreStart, stop: async () => await root.shutdown(), }; }, diff --git a/src/fixtures/stubbed_saved_object_index_pattern.ts b/src/fixtures/stubbed_saved_object_index_pattern.ts index 02e6cb85e341..44b391f14cf9 100644 --- a/src/fixtures/stubbed_saved_object_index_pattern.ts +++ b/src/fixtures/stubbed_saved_object_index_pattern.ts @@ -30,6 +30,7 @@ export function stubbedSavedObjectIndexPattern(id: string | null = null) { timeFieldName: 'timestamp', customFormats: '{}', fields: mockLogstashFields, + title: 'title', }, version: 2, }; diff --git a/src/legacy/core_plugins/elasticsearch/index.js b/src/legacy/core_plugins/elasticsearch/index.js index 599886788604..f90f490d6803 100644 --- a/src/legacy/core_plugins/elasticsearch/index.js +++ b/src/legacy/core_plugins/elasticsearch/index.js @@ -16,18 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -import { first } from 'rxjs/operators'; import { Cluster } from './server/lib/cluster'; import { createProxy } from './server/lib/create_proxy'; export default function (kibana) { - let defaultVars; - return new kibana.Plugin({ require: [], - uiExports: { injectDefaultVars: () => defaultVars }, - async init(server) { // All methods that ES plugin exposes are synchronous so we should get the first // value from all observables here to be able to synchronously return and create @@ -36,16 +31,6 @@ export default function (kibana) { const adminCluster = new Cluster(client); const dataCluster = new Cluster(client); - const esConfig = await server.newPlatform.__internals.elasticsearch.legacy.config$ - .pipe(first()) - .toPromise(); - - defaultVars = { - esRequestTimeout: esConfig.requestTimeout.asMilliseconds(), - esShardTimeout: esConfig.shardTimeout.asMilliseconds(), - esApiVersion: esConfig.apiVersion, - }; - const clusters = new Map(); server.expose('getCluster', (name) => { if (name === 'admin') { diff --git a/src/legacy/plugin_discovery/plugin_spec/plugin_spec_options.d.ts b/src/legacy/plugin_discovery/plugin_spec/plugin_spec_options.d.ts index e51a355cbc8d..e1ed2f57375a 100644 --- a/src/legacy/plugin_discovery/plugin_spec/plugin_spec_options.d.ts +++ b/src/legacy/plugin_discovery/plugin_spec/plugin_spec_options.d.ts @@ -18,14 +18,10 @@ */ import { Server } from '../../server/kbn_server'; import { Capabilities } from '../../../core/server'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SavedObjectsLegacyManagementDefinition } from '../../../core/server/saved_objects/types'; export type InitPluginFunction = (server: Server) => void; export interface UiExports { injectDefaultVars?: (server: Server) => { [key: string]: any }; - savedObjectsManagement?: SavedObjectsLegacyManagementDefinition; - mappings?: unknown; } export interface PluginSpecOptions { diff --git a/src/legacy/plugin_discovery/types.ts b/src/legacy/plugin_discovery/types.ts index 283806f69599..700ca6fa68c9 100644 --- a/src/legacy/plugin_discovery/types.ts +++ b/src/legacy/plugin_discovery/types.ts @@ -19,11 +19,6 @@ import { Server } from '../server/kbn_server'; import { Capabilities } from '../../core/server'; -// Disable lint errors for imports from src/core/* until SavedObjects migration is complete -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SavedObjectsSchemaDefinition } from '../../core/server/saved_objects/schema'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { SavedObjectsLegacyManagementDefinition } from '../../core/server/saved_objects/types'; import { AppCategory } from '../../core/types'; /** @@ -70,8 +65,6 @@ export interface LegacyPluginOptions { home: string[]; mappings: any; migrations: any; - savedObjectSchemas: SavedObjectsSchemaDefinition; - savedObjectsManagement: SavedObjectsLegacyManagementDefinition; visTypes: string[]; embeddableActions?: string[]; embeddableFactories?: string[]; diff --git a/src/legacy/server/kbn_server.d.ts b/src/legacy/server/kbn_server.d.ts index 69fb63fbbd87..663542618375 100644 --- a/src/legacy/server/kbn_server.d.ts +++ b/src/legacy/server/kbn_server.d.ts @@ -17,33 +17,24 @@ * under the License. */ -import { ResponseObject, Server } from 'hapi'; -import { UnwrapPromise } from '@kbn/utility-types'; +import { Server } from 'hapi'; import { TelemetryCollectionManagerPluginSetup } from 'src/plugins/telemetry_collection_manager/server'; import { - ConfigService, CoreSetup, CoreStart, - ElasticsearchServiceSetup, EnvironmentMode, LoggerFactory, - SavedObjectsClientContract, - SavedObjectsLegacyService, - SavedObjectsClientProviderOptions, - IUiSettingsClient, PackageInfo, - LegacyRequest, LegacyServiceSetupDeps, - LegacyServiceStartDeps, LegacyServiceDiscoverPlugins, } from '../../core/server'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LegacyConfig, ILegacyService, ILegacyInternals } from '../../core/server/legacy'; +import { LegacyConfig, ILegacyInternals } from '../../core/server/legacy'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { UiPlugins } from '../../core/server/plugins'; -import { CallClusterWithRequest, ElasticsearchPlugin } from '../core_plugins/elasticsearch'; +import { ElasticsearchPlugin } from '../core_plugins/elasticsearch'; import { UsageCollectionSetup } from '../../plugins/usage_collection/server'; import { HomeServerPluginSetup } from '../../plugins/home/server'; @@ -61,16 +52,9 @@ declare module 'hapi' { interface Server { config: () => KibanaConfig; - savedObjects: SavedObjectsLegacyService; logWithMetadata: (tags: string[], message: string, meta: Record) => void; newPlatform: KbnServer['newPlatform']; } - - interface Request { - getSavedObjectsClient(options?: SavedObjectsClientProviderOptions): SavedObjectsClientContract; - getBasePath(): string; - getUiSettingsService(): IUiSettingsClient; - } } type KbnMixinFunc = (kbnServer: KbnServer, server: Server, config: any) => Promise | void; @@ -86,11 +70,9 @@ export interface KibanaCore { __internals: { elasticsearch: LegacyServiceSetupDeps['core']['elasticsearch']; hapiServer: LegacyServiceSetupDeps['core']['http']['server']; - kibanaMigrator: LegacyServiceStartDeps['core']['savedObjects']['migrator']; legacy: ILegacyInternals; rendering: LegacyServiceSetupDeps['core']['rendering']; uiPlugins: UiPlugins; - savedObjectsClientProvider: LegacyServiceStartDeps['core']['savedObjects']['clientProvider']; }; env: { mode: Readonly; @@ -149,6 +131,3 @@ export default class KbnServer { // Re-export commonly used hapi types. export { Server, Request, ResponseToolkit } from 'hapi'; - -// Re-export commonly accessed api types. -export { SavedObjectsLegacyService, SavedObjectsClient } from 'src/core/server'; diff --git a/src/legacy/server/kbn_server.js b/src/legacy/server/kbn_server.js index 4692262d99bb..a5eefd140c8f 100644 --- a/src/legacy/server/kbn_server.js +++ b/src/legacy/server/kbn_server.js @@ -33,7 +33,6 @@ import pidMixin from './pid'; import configCompleteMixin from './config/complete'; import { optimizeMixin } from '../../optimize'; import * as Plugins from './plugins'; -import { savedObjectsMixin } from './saved_objects/saved_objects_mixin'; import { uiMixin } from '../ui'; import { i18nMixin } from './i18n'; @@ -108,9 +107,6 @@ export default class KbnServer { uiMixin, - // setup saved object routes - savedObjectsMixin, - // setup routes that serve the @kbn/optimizer output optimizeMixin, diff --git a/src/legacy/server/saved_objects/saved_objects_mixin.js b/src/legacy/server/saved_objects/saved_objects_mixin.js deleted file mode 100644 index 96cf2058839c..000000000000 --- a/src/legacy/server/saved_objects/saved_objects_mixin.js +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -// Disable lint errors for imports from src/core/server/saved_objects until SavedObjects migration is complete -/* eslint-disable @kbn/eslint/no-restricted-paths */ -import { SavedObjectsSchema } from '../../../core/server/saved_objects/schema'; -import { - SavedObjectsClient, - SavedObjectsRepository, - exportSavedObjectsToStream, - importSavedObjectsFromStream, - resolveSavedObjectsImportErrors, -} from '../../../core/server/saved_objects'; -import { convertTypesToLegacySchema } from '../../../core/server/saved_objects/utils'; - -export function savedObjectsMixin(kbnServer, server) { - const migrator = kbnServer.newPlatform.__internals.kibanaMigrator; - const typeRegistry = kbnServer.newPlatform.start.core.savedObjects.getTypeRegistry(); - const mappings = migrator.getActiveMappings(); - const allTypes = typeRegistry.getAllTypes().map((t) => t.name); - const visibleTypes = typeRegistry.getVisibleTypes().map((t) => t.name); - const schema = new SavedObjectsSchema(convertTypesToLegacySchema(typeRegistry.getAllTypes())); - - server.decorate('server', 'kibanaMigrator', migrator); - - const serializer = kbnServer.newPlatform.start.core.savedObjects.createSerializer(); - - const createRepository = (callCluster, includedHiddenTypes = []) => { - if (typeof callCluster !== 'function') { - throw new TypeError('Repository requires a "callCluster" function to be provided.'); - } - // throw an exception if an extraType is not defined. - includedHiddenTypes.forEach((type) => { - if (!allTypes.includes(type)) { - throw new Error(`Missing mappings for saved objects type '${type}'`); - } - }); - const combinedTypes = visibleTypes.concat(includedHiddenTypes); - const allowedTypes = [...new Set(combinedTypes)]; - - const config = server.config(); - - return new SavedObjectsRepository({ - index: config.get('kibana.index'), - migrator, - mappings, - typeRegistry, - serializer, - allowedTypes, - callCluster, - }); - }; - - const provider = kbnServer.newPlatform.__internals.savedObjectsClientProvider; - - const service = { - types: visibleTypes, - SavedObjectsClient, - SavedObjectsRepository, - getSavedObjectsRepository: createRepository, - getScopedSavedObjectsClient: (...args) => provider.getClient(...args), - setScopedSavedObjectsClientFactory: (...args) => provider.setClientFactory(...args), - addScopedSavedObjectsClientWrapperFactory: (...args) => - provider.addClientWrapperFactory(...args), - importExport: { - objectLimit: server.config().get('savedObjects.maxImportExportSize'), - importSavedObjects: importSavedObjectsFromStream, - resolveImportErrors: resolveSavedObjectsImportErrors, - getSortedObjectsForExport: exportSavedObjectsToStream, - }, - schema, - }; - server.decorate('server', 'savedObjects', service); - - const savedObjectsClientCache = new WeakMap(); - server.decorate('request', 'getSavedObjectsClient', function (options) { - const request = this; - - if (savedObjectsClientCache.has(request)) { - return savedObjectsClientCache.get(request); - } - - const savedObjectsClient = server.savedObjects.getScopedSavedObjectsClient(request, options); - - savedObjectsClientCache.set(request, savedObjectsClient); - return savedObjectsClient; - }); -} diff --git a/src/legacy/server/saved_objects/saved_objects_mixin.test.js b/src/legacy/server/saved_objects/saved_objects_mixin.test.js deleted file mode 100644 index d1d6c052ad58..000000000000 --- a/src/legacy/server/saved_objects/saved_objects_mixin.test.js +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { savedObjectsMixin } from './saved_objects_mixin'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { mockKibanaMigrator } from '../../../core/server/saved_objects/migrations/kibana/kibana_migrator.mock'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { savedObjectsClientProviderMock } from '../../../core/server/saved_objects/service/lib/scoped_client_provider.mock'; -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { convertLegacyTypes } from '../../../core/server/saved_objects/utils'; -import { SavedObjectTypeRegistry } from '../../../core/server'; -import { coreMock } from '../../../core/server/mocks'; - -const mockConfig = { - get: jest.fn().mockReturnValue('anything'), -}; - -const savedObjectMappings = [ - { - pluginId: 'testtype', - properties: { - testtype: { - properties: { - name: { type: 'keyword' }, - }, - }, - }, - }, - { - pluginId: 'testtype2', - properties: { - doc1: { - properties: { - name: { type: 'keyword' }, - }, - }, - doc2: { - properties: { - name: { type: 'keyword' }, - }, - }, - }, - }, - { - pluginId: 'secretPlugin', - properties: { - hiddentype: { - properties: { - secret: { type: 'keyword' }, - }, - }, - }, - }, -]; - -const savedObjectSchemas = { - hiddentype: { - hidden: true, - }, - doc1: { - indexPattern: 'other-index', - }, -}; - -const savedObjectTypes = convertLegacyTypes( - { - savedObjectMappings, - savedObjectSchemas, - savedObjectMigrations: {}, - }, - mockConfig -); - -const typeRegistry = new SavedObjectTypeRegistry(); -savedObjectTypes.forEach((type) => typeRegistry.registerType(type)); - -const migrator = mockKibanaMigrator.create({ - types: savedObjectTypes, -}); - -describe('Saved Objects Mixin', () => { - let mockKbnServer; - let mockServer; - const mockCallCluster = jest.fn(); - const stubCallCluster = jest.fn(); - const config = { - 'kibana.index': 'kibana.index', - 'savedObjects.maxImportExportSize': 10000, - }; - const stubConfig = jest.fn((key) => { - return config[key]; - }); - - beforeEach(() => { - const clientProvider = savedObjectsClientProviderMock.create(); - mockServer = { - log: jest.fn(), - route: jest.fn(), - decorate: jest.fn(), - config: () => { - return { - get: stubConfig, - }; - }, - plugins: { - elasticsearch: { - getCluster: () => { - return { - callWithRequest: mockCallCluster, - callWithInternalUser: stubCallCluster, - }; - }, - waitUntilReady: jest.fn(), - }, - }, - }; - - const coreStart = coreMock.createStart(); - coreStart.savedObjects.getTypeRegistry.mockReturnValue(typeRegistry); - - mockKbnServer = { - newPlatform: { - __internals: { - kibanaMigrator: migrator, - savedObjectsClientProvider: clientProvider, - }, - setup: { - core: coreMock.createSetup(), - }, - start: { - core: coreStart, - }, - }, - server: mockServer, - ready: () => {}, - pluginSpecs: { - some: () => { - return true; - }, - }, - uiExports: { - savedObjectMappings, - savedObjectSchemas, - }, - }; - }); - - describe('Saved object service', () => { - let service; - - beforeEach(async () => { - await savedObjectsMixin(mockKbnServer, mockServer); - const call = mockServer.decorate.mock.calls.filter( - ([objName, methodName]) => objName === 'server' && methodName === 'savedObjects' - ); - service = call[0][2]; - }); - - it('should return all but hidden types', async () => { - expect(service).toBeDefined(); - expect(service.types).toEqual(['testtype', 'doc1', 'doc2']); - }); - - const mockCallEs = jest.fn(); - describe('repository creation', () => { - it('should not allow a repository with an undefined type', () => { - expect(() => { - service.getSavedObjectsRepository(mockCallEs, ['extraType']); - }).toThrow(new Error("Missing mappings for saved objects type 'extraType'")); - }); - - it('should create a repository without hidden types', () => { - const repository = service.getSavedObjectsRepository(mockCallEs); - expect(repository).toBeDefined(); - expect(repository._allowedTypes).toEqual(['testtype', 'doc1', 'doc2']); - }); - - it('should create a repository with a unique list of allowed types', () => { - const repository = service.getSavedObjectsRepository(mockCallEs, ['doc1', 'doc1', 'doc1']); - expect(repository._allowedTypes).toEqual(['testtype', 'doc1', 'doc2']); - }); - - it('should create a repository with extraTypes minus duplicate', () => { - const repository = service.getSavedObjectsRepository(mockCallEs, [ - 'hiddentype', - 'hiddentype', - ]); - expect(repository._allowedTypes).toEqual(['testtype', 'doc1', 'doc2', 'hiddentype']); - }); - - it('should not allow a repository without a callCluster function', () => { - expect(() => { - service.getSavedObjectsRepository({}); - }).toThrow(new Error('Repository requires a "callCluster" function to be provided.')); - }); - }); - - describe('get client', () => { - it('should have a method to get the client', () => { - expect(service).toHaveProperty('getScopedSavedObjectsClient'); - }); - - it('should have a method to set the client factory', () => { - expect(service).toHaveProperty('setScopedSavedObjectsClientFactory'); - }); - - it('should have a method to add a client wrapper factory', () => { - expect(service).toHaveProperty('addScopedSavedObjectsClientWrapperFactory'); - }); - - it('should allow you to set a scoped saved objects client factory', () => { - expect(() => { - service.setScopedSavedObjectsClientFactory({}); - }).not.toThrowError(); - }); - - it('should allow you to add a scoped saved objects client wrapper factory', () => { - expect(() => { - service.addScopedSavedObjectsClientWrapperFactory({}); - }).not.toThrowError(); - }); - }); - - describe('#getSavedObjectsClient', () => { - let getSavedObjectsClient; - - beforeEach(() => { - savedObjectsMixin(mockKbnServer, mockServer); - const call = mockServer.decorate.mock.calls.filter( - ([objName, methodName]) => objName === 'request' && methodName === 'getSavedObjectsClient' - ); - getSavedObjectsClient = call[0][2]; - }); - - it('should be callable', () => { - mockServer.savedObjects = service; - getSavedObjectsClient = getSavedObjectsClient.bind({}); - expect(() => { - getSavedObjectsClient(); - }).not.toThrowError(); - }); - - it('should use cached request object', () => { - mockServer.savedObjects = service; - getSavedObjectsClient = getSavedObjectsClient.bind({ _test: 'me' }); - const savedObjectsClient = getSavedObjectsClient(); - expect(getSavedObjectsClient()).toEqual(savedObjectsClient); - }); - }); - }); -}); diff --git a/src/legacy/ui/ui_exports/__tests__/collect_ui_exports.js b/src/legacy/ui/ui_exports/__tests__/collect_ui_exports.js deleted file mode 100644 index 5b2af9f82333..000000000000 --- a/src/legacy/ui/ui_exports/__tests__/collect_ui_exports.js +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import expect from '@kbn/expect'; - -import { PluginPack } from '../../../plugin_discovery'; - -import { collectUiExports } from '../collect_ui_exports'; - -const specs = new PluginPack({ - path: '/dev/null', - pkg: { - name: 'test', - version: 'kibana', - }, - provider({ Plugin }) { - return [ - new Plugin({ - id: 'test', - uiExports: { - savedObjectSchemas: { - foo: { - isNamespaceAgnostic: true, - }, - }, - }, - }), - new Plugin({ - id: 'test2', - uiExports: { - savedObjectSchemas: { - bar: { - isNamespaceAgnostic: true, - }, - }, - }, - }), - ]; - }, -}).getPluginSpecs(); - -describe('plugin discovery', () => { - describe('collectUiExports()', () => { - it('merges uiExports from all provided plugin specs', () => { - const uiExports = collectUiExports(specs); - - expect(uiExports.savedObjectSchemas).to.eql({ - foo: { - isNamespaceAgnostic: true, - }, - bar: { - isNamespaceAgnostic: true, - }, - }); - }); - - it(`throws an error when migrations and mappings aren't defined in the same plugin`, () => { - const invalidSpecs = new PluginPack({ - path: '/dev/null', - pkg: { - name: 'test', - version: 'kibana', - }, - provider({ Plugin }) { - return [ - new Plugin({ - id: 'test', - uiExports: { - mappings: { - 'test-type': { - properties: {}, - }, - }, - }, - }), - new Plugin({ - id: 'test2', - uiExports: { - migrations: { - 'test-type': { - '1.2.3': (doc) => { - return doc; - }, - }, - }, - }, - }), - ]; - }, - }).getPluginSpecs(); - expect(() => collectUiExports(invalidSpecs)).to.throwError((err) => { - expect(err).to.be.a(Error); - expect(err).to.have.property( - 'message', - 'Migrations and mappings must be defined together in the uiExports of a single plugin. ' + - 'test2 defines migrations for types test-type but does not define their mappings.' - ); - }); - }); - }); -}); diff --git a/src/legacy/ui/ui_render/ui_render_mixin.js b/src/legacy/ui/ui_render/ui_render_mixin.js index cd8dcf5aff71..e3b7c1e0c3ff 100644 --- a/src/legacy/ui/ui_render/ui_render_mixin.js +++ b/src/legacy/ui/ui_render/ui_render_mixin.js @@ -193,13 +193,11 @@ export function uiRenderMixin(kbnServer, server, config) { async function renderApp(h) { const app = { getId: () => 'core' }; const { http } = kbnServer.newPlatform.setup.core; - const { - rendering, - legacy, - savedObjectsClientProvider: savedObjects, - } = kbnServer.newPlatform.__internals; + const { savedObjects } = kbnServer.newPlatform.start.core; + const { rendering, legacy } = kbnServer.newPlatform.__internals; + const req = KibanaRequest.from(h.request); const uiSettings = kbnServer.newPlatform.start.core.uiSettings.asScopedToClient( - savedObjects.getClient(h.request) + savedObjects.getScopedClient(req) ); const vars = await legacy.getVars(app.getId(), h.request, { apmConfig: getApmConfig(h.request.path), diff --git a/src/legacy/utils/index.js b/src/legacy/utils/index.js index 529b1ddfd8a4..e2e2331b3aea 100644 --- a/src/legacy/utils/index.js +++ b/src/legacy/utils/index.js @@ -17,8 +17,6 @@ * under the License. */ -export { BinderBase } from './binder'; -export { BinderFor } from './binder_for'; export { deepCloneWithBuffers } from './deep_clone_with_buffers'; export { unset } from './unset'; export { IS_KIBANA_DISTRIBUTABLE } from './artifact_type'; diff --git a/src/plugins/dashboard/public/application/actions/open_replace_panel_flyout.tsx b/src/plugins/dashboard/public/application/actions/open_replace_panel_flyout.tsx index c676ca052d68..54a294fd2f4a 100644 --- a/src/plugins/dashboard/public/application/actions/open_replace_panel_flyout.tsx +++ b/src/plugins/dashboard/public/application/actions/open_replace_panel_flyout.tsx @@ -60,7 +60,8 @@ export async function openReplacePanelFlyout(options: { /> ), { - 'data-test-subj': 'replacePanelFlyout', + 'data-test-subj': 'dashboardReplacePanel', + ownFocus: true, } ); } diff --git a/src/plugins/dashboard/public/application/actions/replace_panel_flyout.tsx b/src/plugins/dashboard/public/application/actions/replace_panel_flyout.tsx index 0000f63c48c2..4e228bc1a7a0 100644 --- a/src/plugins/dashboard/public/application/actions/replace_panel_flyout.tsx +++ b/src/plugins/dashboard/public/application/actions/replace_panel_flyout.tsx @@ -19,16 +19,15 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; -import _ from 'lodash'; -import { EuiFlyout, EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; +import { EuiFlyoutBody, EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; import { NotificationsStart, Toast } from 'src/core/public'; import { DashboardPanelState } from '../embeddable'; import { - IContainer, - IEmbeddable, EmbeddableInput, EmbeddableOutput, EmbeddableStart, + IContainer, + IEmbeddable, SavedObjectEmbeddableInput, } from '../../embeddable_plugin'; @@ -122,7 +121,7 @@ export class ReplacePanelFlyout extends React.Component { const panelToReplace = 'Replace panel ' + this.props.panelToRemove.getTitle() + ' with:'; return ( - + <>

@@ -131,7 +130,7 @@ export class ReplacePanelFlyout extends React.Component { {savedObjectsFinder} - + ); } } diff --git a/src/plugins/data/common/constants.ts b/src/plugins/data/common/constants.ts index 22db1552e430..43120583bd3a 100644 --- a/src/plugins/data/common/constants.ts +++ b/src/plugins/data/common/constants.ts @@ -32,6 +32,7 @@ export const UI_SETTINGS = { COURIER_MAX_CONCURRENT_SHARD_REQUESTS: 'courier:maxConcurrentShardRequests', COURIER_BATCH_SEARCHES: 'courier:batchSearches', SEARCH_INCLUDE_FROZEN: 'search:includeFrozen', + SEARCH_TIMEOUT: 'search:timeout', HISTOGRAM_BAR_TARGET: 'histogram:barTarget', HISTOGRAM_MAX_BARS: 'histogram:maxBars', HISTORY_LIMIT: 'history:limit', diff --git a/src/plugins/data/common/field_formats/converters/duration.test.ts b/src/plugins/data/common/field_formats/converters/duration.test.ts index d6205d54bd70..69163842f349 100644 --- a/src/plugins/data/common/field_formats/converters/duration.test.ts +++ b/src/plugins/data/common/field_formats/converters/duration.test.ts @@ -24,11 +24,16 @@ describe('Duration Format', () => { inputFormat: 'seconds', outputFormat: 'humanize', outputPrecision: undefined, + showSuffix: undefined, fixtures: [ { input: -60, output: 'minus a minute', }, + { + input: 1, + output: 'a few seconds', + }, { input: 60, output: 'a minute', @@ -44,6 +49,7 @@ describe('Duration Format', () => { inputFormat: 'minutes', outputFormat: 'humanize', outputPrecision: undefined, + showSuffix: undefined, fixtures: [ { input: -60, @@ -64,6 +70,7 @@ describe('Duration Format', () => { inputFormat: 'minutes', outputFormat: 'asHours', outputPrecision: undefined, + showSuffix: undefined, fixtures: [ { input: -60, @@ -84,6 +91,7 @@ describe('Duration Format', () => { inputFormat: 'seconds', outputFormat: 'asSeconds', outputPrecision: 0, + showSuffix: undefined, fixtures: [ { input: -60, @@ -104,6 +112,7 @@ describe('Duration Format', () => { inputFormat: 'seconds', outputFormat: 'asSeconds', outputPrecision: 2, + showSuffix: undefined, fixtures: [ { input: -60, @@ -124,15 +133,34 @@ describe('Duration Format', () => { ], }); + testCase({ + inputFormat: 'seconds', + outputFormat: 'asSeconds', + outputPrecision: 0, + showSuffix: true, + fixtures: [ + { + input: -60, + output: '-60 Seconds', + }, + { + input: -32.333, + output: '-32 Seconds', + }, + ], + }); + function testCase({ inputFormat, outputFormat, outputPrecision, + showSuffix, fixtures, }: { inputFormat: string; outputFormat: string; outputPrecision: number | undefined; + showSuffix: boolean | undefined; fixtures: any[]; }) { fixtures.forEach((fixture: Record) => { @@ -143,7 +171,7 @@ describe('Duration Format', () => { outputPrecision ? `, ${outputPrecision} decimals` : '' }`, () => { const duration = new DurationFormat( - { inputFormat, outputFormat, outputPrecision }, + { inputFormat, outputFormat, outputPrecision, showSuffix }, jest.fn() ); expect(duration.convert(input)).toBe(output); diff --git a/src/plugins/data/common/field_formats/converters/duration.ts b/src/plugins/data/common/field_formats/converters/duration.ts index 53c2aba98120..a3ce3d4dfd79 100644 --- a/src/plugins/data/common/field_formats/converters/duration.ts +++ b/src/plugins/data/common/field_formats/converters/duration.ts @@ -190,6 +190,7 @@ export class DurationFormat extends FieldFormat { const inputFormat = this.param('inputFormat'); const outputFormat = this.param('outputFormat') as keyof Duration; const outputPrecision = this.param('outputPrecision'); + const showSuffix = Boolean(this.param('showSuffix')); const human = this.isHuman(); const prefix = val < 0 && human @@ -200,6 +201,9 @@ export class DurationFormat extends FieldFormat { const duration = parseInputAsDuration(val, inputFormat) as Record; const formatted = duration[outputFormat](); const precise = human ? formatted : formatted.toFixed(outputPrecision); - return prefix + precise; + const type = outputFormats.find(({ method }) => method === outputFormat); + const suffix = showSuffix && type ? ` ${type.text}` : ''; + + return prefix + precise + suffix; }; } diff --git a/src/plugins/data/common/index_patterns/index_patterns/__snapshots__/index_pattern.test.ts.snap b/src/plugins/data/common/index_patterns/index_patterns/__snapshots__/index_pattern.test.ts.snap index a0c380ec55bf..1871627da76d 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/__snapshots__/index_pattern.test.ts.snap +++ b/src/plugins/data/common/index_patterns/index_patterns/__snapshots__/index_pattern.test.ts.snap @@ -631,7 +631,7 @@ Object { "id": "test-pattern", "sourceFilters": undefined, "timeFieldName": "timestamp", - "title": "test-pattern", + "title": "title", "typeMeta": undefined, "version": 2, } diff --git a/src/plugins/data/common/index_patterns/index_patterns/index_pattern.test.ts b/src/plugins/data/common/index_patterns/index_patterns/index_pattern.test.ts index f037a71b508a..f49897c47d56 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/index_pattern.test.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/index_pattern.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { defaults, map, last, get } from 'lodash'; +import { defaults, map, last } from 'lodash'; import { IndexPattern } from './index_pattern'; @@ -29,7 +29,7 @@ import { stubbedSavedObjectIndexPattern } from '../../../../../fixtures/stubbed_ import { IndexPatternField } from '../fields'; import { fieldFormatsMock } from '../../field_formats/mocks'; -import { FieldFormat } from '../..'; +import { FieldFormat, IndexPatternsService } from '../..'; class MockFieldFormatter {} @@ -116,6 +116,7 @@ function create(id: string, payload?: any): Promise { apiClient, patternCache, fieldFormats: fieldFormatsMock, + indexPatternsService: {} as IndexPatternsService, onNotification: () => {}, onError: () => {}, shortDotsEnable: false, @@ -151,7 +152,6 @@ describe('IndexPattern', () => { expect(indexPattern).toHaveProperty('getNonScriptedFields'); expect(indexPattern).toHaveProperty('addScriptedField'); expect(indexPattern).toHaveProperty('removeScriptedField'); - expect(indexPattern).toHaveProperty('save'); // properties expect(indexPattern).toHaveProperty('fields'); @@ -389,60 +389,4 @@ describe('IndexPattern', () => { }); }); }); - - test('should handle version conflicts', async () => { - setDocsourcePayload(null, { - id: 'foo', - version: 'foo', - attributes: { - title: 'something', - }, - }); - // Create a normal index pattern - const pattern = new IndexPattern('foo', { - savedObjectsClient: savedObjectsClient as any, - apiClient, - patternCache, - fieldFormats: fieldFormatsMock, - onNotification: () => {}, - onError: () => {}, - shortDotsEnable: false, - metaFields: [], - }); - await pattern.init(); - - expect(get(pattern, 'version')).toBe('fooa'); - - // Create the same one - we're going to handle concurrency - const samePattern = new IndexPattern('foo', { - savedObjectsClient: savedObjectsClient as any, - apiClient, - patternCache, - fieldFormats: fieldFormatsMock, - onNotification: () => {}, - onError: () => {}, - shortDotsEnable: false, - metaFields: [], - }); - await samePattern.init(); - - expect(get(samePattern, 'version')).toBe('fooaa'); - - // This will conflict because samePattern did a save (from refreshFields) - // but the resave should work fine - pattern.title = 'foo2'; - await pattern.save(); - - // This should not be able to recover - samePattern.title = 'foo3'; - - let result; - try { - await samePattern.save(); - } catch (err) { - result = err; - } - - expect(result.res.status).toBe(409); - }); }); diff --git a/src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts b/src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts index 055880857358..76f1a5e59d0e 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/index_pattern.ts @@ -41,8 +41,8 @@ import { PatternCache } from './_pattern_cache'; import { expandShorthand, FieldMappingSpec, MappingObject } from '../../field_mapping'; import { IndexPatternSpec, TypeMeta, FieldSpec, SourceFilter } from '../types'; import { SerializedFieldFormat } from '../../../../expressions/common'; +import { IndexPatternsService } from '..'; -const MAX_ATTEMPTS_TO_RESOLVE_CONFLICTS = 3; const savedObjectType = 'index-pattern'; interface IndexPatternDeps { @@ -50,6 +50,7 @@ interface IndexPatternDeps { apiClient: IIndexPatternsApiClient; patternCache: PatternCache; fieldFormats: FieldFormatsStartCommon; + indexPatternsService: IndexPatternsService; onNotification: OnNotification; onError: OnError; shortDotsEnable: boolean; @@ -70,17 +71,18 @@ export class IndexPattern implements IIndexPattern { public flattenHit: any; public metaFields: string[]; - private version: string | undefined; + public version: string | undefined; private savedObjectsClient: SavedObjectsClientCommon; private patternCache: PatternCache; public sourceFilters?: SourceFilter[]; - private originalBody: { [key: string]: any } = {}; + // todo make read only, update via method or factor out + public originalBody: { [key: string]: any } = {}; public fieldsFetcher: any; // probably want to factor out any direct usage and change to private + private indexPatternsService: IndexPatternsService; private shortDotsEnable: boolean = false; private fieldFormats: FieldFormatsStartCommon; private onNotification: OnNotification; private onError: OnError; - private apiClient: IIndexPatternsApiClient; private mapping: MappingObject = expandShorthand({ title: ES_FIELD_TYPES.TEXT, @@ -111,6 +113,7 @@ export class IndexPattern implements IIndexPattern { apiClient, patternCache, fieldFormats, + indexPatternsService, onNotification, onError, shortDotsEnable = false, @@ -121,6 +124,7 @@ export class IndexPattern implements IIndexPattern { this.savedObjectsClient = savedObjectsClient; this.patternCache = patternCache; this.fieldFormats = fieldFormats; + this.indexPatternsService = indexPatternsService; this.onNotification = onNotification; this.onError = onError; @@ -128,7 +132,6 @@ export class IndexPattern implements IIndexPattern { this.metaFields = metaFields; this.fields = fieldList([], this.shortDotsEnable); - this.apiClient = apiClient; this.fieldsFetcher = createFieldsFetcher(this, apiClient, metaFields); this.flattenHit = flattenHitWrapper(this, metaFields); this.formatHit = formatHitProvider( @@ -392,8 +395,6 @@ export class IndexPattern implements IIndexPattern { } else { throw err; } - - await this.save(); } } @@ -402,7 +403,6 @@ export class IndexPattern implements IIndexPattern { if (field) { this.fields.remove(field); } - return this.save(); } async popularizeField(fieldName: string, unit = 1) { @@ -523,92 +523,6 @@ export class IndexPattern implements IIndexPattern { return await _create(potentialDuplicateByTitle.id); } - async save(saveAttempts: number = 0): Promise { - if (!this.id) return; - const body = this.prepBody(); - - const originalChangedKeys: string[] = []; - Object.entries(body).forEach(([key, value]) => { - if (value !== this.originalBody[key]) { - originalChangedKeys.push(key); - } - }); - - return this.savedObjectsClient - .update(savedObjectType, this.id, body, { version: this.version }) - .then((resp) => { - this.id = resp.id; - this.version = resp.version; - }) - .catch((err) => { - if ( - _.get(err, 'res.status') === 409 && - saveAttempts++ < MAX_ATTEMPTS_TO_RESOLVE_CONFLICTS - ) { - const samePattern = new IndexPattern(this.id, { - savedObjectsClient: this.savedObjectsClient, - apiClient: this.apiClient, - patternCache: this.patternCache, - fieldFormats: this.fieldFormats, - onNotification: this.onNotification, - onError: this.onError, - shortDotsEnable: this.shortDotsEnable, - metaFields: this.metaFields, - }); - - return samePattern.init().then(() => { - // What keys changed from now and what the server returned - const updatedBody = samePattern.prepBody(); - - // Build a list of changed keys from the server response - // and ensure we ignore the key if the server response - // is the same as the original response (since that is expected - // if we made a change in that key) - - const serverChangedKeys: string[] = []; - Object.entries(updatedBody).forEach(([key, value]) => { - if (value !== (body as any)[key] && value !== this.originalBody[key]) { - serverChangedKeys.push(key); - } - }); - - let unresolvedCollision = false; - for (const originalKey of originalChangedKeys) { - for (const serverKey of serverChangedKeys) { - if (originalKey === serverKey) { - unresolvedCollision = true; - break; - } - } - } - - if (unresolvedCollision) { - const title = i18n.translate('data.indexPatterns.unableWriteLabel', { - defaultMessage: - 'Unable to write index pattern! Refresh the page to get the most up to date changes for this index pattern.', - }); - - this.onNotification({ title, color: 'danger' }); - throw err; - } - - // Set the updated response on this object - serverChangedKeys.forEach((key) => { - (this as any)[key] = (samePattern as any)[key]; - }); - this.version = samePattern.version; - - // Clear cache - this.patternCache.clear(this.id!); - - // Try the save again - return this.save(saveAttempts); - }); - } - throw err; - }); - } - async _fetchFields() { const fields = await this.fieldsFetcher.fetch(this); const scripted = this.getScriptedFields().map((field) => field.spec); @@ -624,30 +538,37 @@ export class IndexPattern implements IIndexPattern { } refreshFields() { - return this._fetchFields() - .then(() => this.save()) - .catch((err) => { - // https://github.com/elastic/kibana/issues/9224 - // This call will attempt to remap fields from the matching - // ES index which may not actually exist. In that scenario, - // we still want to notify the user that there is a problem - // but we do not want to potentially make any pages unusable - // so do not rethrow the error here - - if (err instanceof IndexPatternMissingIndices) { - this.onNotification({ title: (err as any).message, color: 'danger', iconType: 'alert' }); - return []; - } + return ( + this._fetchFields() + // todo + .then(() => this.indexPatternsService.save(this)) + .catch((err) => { + // https://github.com/elastic/kibana/issues/9224 + // This call will attempt to remap fields from the matching + // ES index which may not actually exist. In that scenario, + // we still want to notify the user that there is a problem + // but we do not want to potentially make any pages unusable + // so do not rethrow the error here + + if (err instanceof IndexPatternMissingIndices) { + this.onNotification({ + title: (err as any).message, + color: 'danger', + iconType: 'alert', + }); + return []; + } - this.onError(err, { - title: i18n.translate('data.indexPatterns.fetchFieldErrorTitle', { - defaultMessage: 'Error fetching fields for index pattern {title} (ID: {id})', - values: { - id: this.id, - title: this.title, - }, - }), - }); - }); + this.onError(err, { + title: i18n.translate('data.indexPatterns.fetchFieldErrorTitle', { + defaultMessage: 'Error fetching fields for index pattern {title} (ID: {id})', + values: { + id: this.id, + title: this.title, + }, + }), + }); + }) + ); } } diff --git a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.test.ts b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.test.ts index 8223b3104212..c79c7900148e 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.test.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.test.ts @@ -17,28 +17,26 @@ * under the License. */ -import { IndexPatternsService } from './index_patterns'; +import { defaults } from 'lodash'; +import { IndexPatternsService } from '.'; import { fieldFormatsMock } from '../../field_formats/mocks'; -import { - UiSettingsCommon, - IIndexPatternsApiClient, - SavedObjectsClientCommon, - SavedObject, -} from '../types'; +import { stubbedSavedObjectIndexPattern } from '../../../../../fixtures/stubbed_saved_object_index_pattern'; +import { UiSettingsCommon, SavedObjectsClientCommon, SavedObject } from '../types'; + +const createFieldsFetcher = jest.fn().mockImplementation(() => ({ + getFieldsForWildcard: jest.fn().mockImplementation(() => { + return new Promise((resolve) => resolve([])); + }), + every: jest.fn(), +})); const fieldFormats = fieldFormatsMock; -jest.mock('./index_pattern', () => { - class IndexPattern { - init = async () => { - return this; - }; - } +let object: any = {}; - return { - IndexPattern, - }; -}); +function setDocsourcePayload(id: string | null, providedPayload: any) { + object = defaults(providedPayload || {}, stubbedSavedObjectIndexPattern(id)); +} describe('IndexPatterns', () => { let indexPatterns: IndexPatternsService; @@ -53,6 +51,25 @@ describe('IndexPatterns', () => { > ); savedObjectsClient.delete = jest.fn(() => Promise.resolve({}) as Promise); + savedObjectsClient.get = jest.fn().mockImplementation(() => object); + savedObjectsClient.create = jest.fn(); + savedObjectsClient.update = jest + .fn() + .mockImplementation(async (type, id, body, { version }) => { + if (object.version !== version) { + throw new Object({ + res: { + status: 409, + }, + }); + } + object.attributes.title = body.title; + object.version += 'a'; + return { + id: object.id, + version: object.version, + }; + }); indexPatterns = new IndexPatternsService({ uiSettings: ({ @@ -60,7 +77,7 @@ describe('IndexPatterns', () => { getAll: () => {}, } as any) as UiSettingsCommon, savedObjectsClient: (savedObjectsClient as unknown) as SavedObjectsClientCommon, - apiClient: {} as IIndexPatternsApiClient, + apiClient: createFieldsFetcher(), fieldFormats, onNotification: () => {}, onError: () => {}, @@ -70,6 +87,14 @@ describe('IndexPatterns', () => { test('does cache gets for the same id', async () => { const id = '1'; + setDocsourcePayload(id, { + id: 'foo', + version: 'foo', + attributes: { + title: 'something', + }, + }); + const indexPattern = await indexPatterns.get(id); expect(indexPattern).toBeDefined(); @@ -107,4 +132,41 @@ describe('IndexPatterns', () => { await indexPatterns.delete(id); expect(indexPattern).not.toBe(await indexPatterns.get(id)); }); + + test('should handle version conflicts', async () => { + setDocsourcePayload(null, { + id: 'foo', + version: 'foo', + attributes: { + title: 'something', + }, + }); + + // Create a normal index patterns + const pattern = await indexPatterns.make('foo'); + + expect(pattern.version).toBe('fooa'); + + // Create the same one - we're going to handle concurrency + const samePattern = await indexPatterns.make('foo'); + + expect(samePattern.version).toBe('fooaa'); + + // This will conflict because samePattern did a save (from refreshFields) + // but the resave should work fine + pattern.title = 'foo2'; + await indexPatterns.save(pattern); + + // This should not be able to recover + samePattern.title = 'foo3'; + + let result; + try { + await indexPatterns.save(samePattern); + } catch (err) { + result = err; + } + + expect(result.res.status).toBe(409); + }); }); diff --git a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts index fe0d14b2d9c1..88a7e9f6cef4 100644 --- a/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts +++ b/src/plugins/data/common/index_patterns/index_patterns/index_patterns.ts @@ -17,6 +17,7 @@ * under the License. */ +import { i18n } from '@kbn/i18n'; import { SavedObjectsClientCommon } from '../..'; import { createIndexPatternCache } from '.'; @@ -37,6 +38,8 @@ import { FieldFormatsStartCommon } from '../../field_formats'; import { UI_SETTINGS, SavedObject } from '../../../common'; const indexPatternCache = createIndexPatternCache(); +const MAX_ATTEMPTS_TO_RESOLVE_CONFLICTS = 3; +const savedObjectType = 'index-pattern'; type IndexPatternCachedFieldType = 'id' | 'title'; @@ -181,6 +184,7 @@ export class IndexPatternsService { apiClient: this.apiClient, patternCache: indexPatternCache, fieldFormats: this.fieldFormats, + indexPatternsService: this, onNotification: this.onNotification, onError: this.onError, shortDotsEnable, @@ -191,6 +195,93 @@ export class IndexPatternsService { return indexPattern; } + async save(indexPattern: IndexPattern, saveAttempts: number = 0): Promise { + if (!indexPattern.id) return; + const shortDotsEnable = await this.config.get(UI_SETTINGS.SHORT_DOTS_ENABLE); + const metaFields = await this.config.get(UI_SETTINGS.META_FIELDS); + + const body = indexPattern.prepBody(); + + const originalChangedKeys: string[] = []; + Object.entries(body).forEach(([key, value]) => { + if (value !== indexPattern.originalBody[key]) { + originalChangedKeys.push(key); + } + }); + + return this.savedObjectsClient + .update(savedObjectType, indexPattern.id, body, { version: indexPattern.version }) + .then((resp) => { + indexPattern.id = resp.id; + indexPattern.version = resp.version; + }) + .catch((err) => { + if (err?.res?.status === 409 && saveAttempts++ < MAX_ATTEMPTS_TO_RESOLVE_CONFLICTS) { + const samePattern = new IndexPattern(indexPattern.id, { + savedObjectsClient: this.savedObjectsClient, + apiClient: this.apiClient, + patternCache: indexPatternCache, + fieldFormats: this.fieldFormats, + indexPatternsService: this, + onNotification: this.onNotification, + onError: this.onError, + shortDotsEnable, + metaFields, + }); + + return samePattern.init().then(() => { + // What keys changed from now and what the server returned + const updatedBody = samePattern.prepBody(); + + // Build a list of changed keys from the server response + // and ensure we ignore the key if the server response + // is the same as the original response (since that is expected + // if we made a change in that key) + + const serverChangedKeys: string[] = []; + Object.entries(updatedBody).forEach(([key, value]) => { + if (value !== (body as any)[key] && value !== indexPattern.originalBody[key]) { + serverChangedKeys.push(key); + } + }); + + let unresolvedCollision = false; + for (const originalKey of originalChangedKeys) { + for (const serverKey of serverChangedKeys) { + if (originalKey === serverKey) { + unresolvedCollision = true; + break; + } + } + } + + if (unresolvedCollision) { + const title = i18n.translate('data.indexPatterns.unableWriteLabel', { + defaultMessage: + 'Unable to write index pattern! Refresh the page to get the most up to date changes for this index pattern.', + }); + + this.onNotification({ title, color: 'danger' }); + throw err; + } + + // Set the updated response on this object + serverChangedKeys.forEach((key) => { + (indexPattern as any)[key] = (samePattern as any)[key]; + }); + indexPattern.version = samePattern.version; + + // Clear cache + indexPatternCache.clear(indexPattern.id!); + + // Try the save again + return this.save(indexPattern, saveAttempts); + }); + } + throw err; + }); + } + async make(id?: string): Promise { const shortDotsEnable = await this.config.get(UI_SETTINGS.SHORT_DOTS_ENABLE); const metaFields = await this.config.get(UI_SETTINGS.META_FIELDS); @@ -200,6 +291,7 @@ export class IndexPatternsService { apiClient: this.apiClient, patternCache: indexPatternCache, fieldFormats: this.fieldFormats, + indexPatternsService: this, onNotification: this.onNotification, onError: this.onError, shortDotsEnable, diff --git a/src/plugins/data/common/search/es_search/index.ts b/src/plugins/data/common/search/es_search/index.ts index 54757b53b866..d8f7b5091eb8 100644 --- a/src/plugins/data/common/search/es_search/index.ts +++ b/src/plugins/data/common/search/es_search/index.ts @@ -17,10 +17,4 @@ * under the License. */ -export { - ISearchRequestParams, - IEsSearchRequest, - IEsSearchResponse, - ES_SEARCH_STRATEGY, - ISearchOptions, -} from './types'; +export * from './types'; diff --git a/src/plugins/data/common/search/es_search/types.ts b/src/plugins/data/common/search/es_search/types.ts index 89faa5b7119c..81124c1e095f 100644 --- a/src/plugins/data/common/search/es_search/types.ts +++ b/src/plugins/data/common/search/es_search/types.ts @@ -53,3 +53,6 @@ export interface IEsSearchResponse extends IKibanaSearchResponse { isPartial?: boolean; rawResponse: SearchResponse; } + +export const isEsResponse = (response: any): response is IEsSearchResponse => + response && response.rawResponse; diff --git a/src/plugins/data/common/search/index.ts b/src/plugins/data/common/search/index.ts index 3bfb0ddb89aa..061974d86024 100644 --- a/src/plugins/data/common/search/index.ts +++ b/src/plugins/data/common/search/index.ts @@ -22,11 +22,4 @@ export * from './es_search'; export * from './expressions'; export * from './tabify'; export * from './types'; - -export { - IEsSearchRequest, - IEsSearchResponse, - ES_SEARCH_STRATEGY, - ISearchRequestParams, - ISearchOptions, -} from './es_search'; +export * from './es_search'; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index f7b4111df517..553ee6bde5f2 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -429,6 +429,7 @@ export { TimeHistory, TimefilterContract, TimeHistoryContract, + QueryStateChange, } from './query'; export { diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index c2cc2fdc3c13..27d4ea49f9eb 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -693,7 +693,6 @@ export const getKbnTypeNames: () => string[]; // // @public (undocumented) export function getSearchParamsFromRequest(searchRequest: SearchRequest, dependencies: { - esShardTimeout: number; getConfig: GetConfigFn; }): ISearchRequestParams; @@ -912,7 +911,7 @@ export type IMetricAggType = MetricAggType; // @public (undocumented) export class IndexPattern implements IIndexPattern { // Warning: (ae-forgotten-export) The symbol "IndexPatternDeps" needs to be exported by the entry point index.d.ts - constructor(id: string | undefined, { savedObjectsClient, apiClient, patternCache, fieldFormats, onNotification, onError, shortDotsEnable, metaFields, }: IndexPatternDeps); + constructor(id: string | undefined, { savedObjectsClient, apiClient, patternCache, fieldFormats, indexPatternsService, onNotification, onError, shortDotsEnable, metaFields, }: IndexPatternDeps); // (undocumented) addScriptedField(name: string, script: string, fieldType: string | undefined, lang: string): Promise; // (undocumented) @@ -986,6 +985,10 @@ export class IndexPattern implements IIndexPattern { // (undocumented) metaFields: string[]; // (undocumented) + originalBody: { + [key: string]: any; + }; + // (undocumented) popularizeField(fieldName: string, unit?: number): Promise; // (undocumented) prepBody(): { @@ -1001,9 +1004,7 @@ export class IndexPattern implements IIndexPattern { // (undocumented) refreshFields(): Promise; // (undocumented) - removeScriptedField(fieldName: string): Promise; - // (undocumented) - save(saveAttempts?: number): Promise; + removeScriptedField(fieldName: string): void; // Warning: (ae-forgotten-export) The symbol "SourceFilter" needs to be exported by the entry point index.d.ts // // (undocumented) @@ -1018,7 +1019,9 @@ export class IndexPattern implements IIndexPattern { type: string | undefined; // (undocumented) typeMeta?: IndexPatternTypeMeta; - } + // (undocumented) + version: string | undefined; +} // Warning: (ae-missing-release-tag) "AggregationRestrictions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1461,6 +1464,17 @@ export interface QueryState { time?: TimeRange; } +// Warning: (ae-forgotten-export) The symbol "QueryStateChangePartial" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "QueryStateChange" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface QueryStateChange extends QueryStateChangePartial { + // (undocumented) + appFilters?: boolean; + // (undocumented) + globalFilters?: boolean; +} + // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "QueryStringInput" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1678,8 +1692,8 @@ export const search: { // Warning: (ae-missing-release-tag) "SearchBar" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const SearchBar: React.ComponentClass, "query" | "isLoading" | "filters" | "onRefresh" | "onRefreshChange" | "refreshInterval" | "indexPatterns" | "dataTestSubj" | "customSubmitButton" | "screenTitle" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "indicateNoData" | "timeHistory" | "onFiltersUpdated">, any> & { - WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; +export const SearchBar: React.ComponentClass, "query" | "isLoading" | "filters" | "onRefresh" | "onRefreshChange" | "refreshInterval" | "indexPatterns" | "dataTestSubj" | "timeHistory" | "customSubmitButton" | "screenTitle" | "showQueryBar" | "showQueryInput" | "showFilterBar" | "showDatePicker" | "showAutoRefreshOnly" | "isRefreshPaused" | "dateRangeFrom" | "dateRangeTo" | "showSaveQuery" | "savedQuery" | "onQueryChange" | "onQuerySubmit" | "onSaved" | "onSavedQueryUpdated" | "onClearSavedQuery" | "indicateNoData" | "onFiltersUpdated">, any> & { + WrappedComponent: React.ComponentType & ReactIntl.InjectedIntlProps>; }; // Warning: (ae-forgotten-export) The symbol "SearchBarOwnProps" needs to be exported by the entry point index.d.ts @@ -1711,7 +1725,7 @@ export interface SearchError { // // @public (undocumented) export class SearchInterceptor { - constructor(deps: SearchInterceptorDeps, requestTimeout?: number | undefined); + constructor(deps: SearchInterceptorDeps); // @internal protected abortController: AbortController; // @internal (undocumented) @@ -1725,13 +1739,14 @@ export class SearchInterceptor { protected longRunningToast?: Toast; // @internal protected pendingCount$: BehaviorSubject; - // (undocumented) - protected readonly requestTimeout?: number | undefined; - // (undocumented) + // @internal (undocumented) protected runSearch(request: IEsSearchRequest, signal: AbortSignal, strategy?: string): Observable; search(request: IEsSearchRequest, options?: ISearchOptions): Observable; - // (undocumented) - protected setupTimers(options?: ISearchOptions): { + // @internal (undocumented) + protected setupAbortSignal({ abortSignal, timeout, }: { + abortSignal?: AbortSignal; + timeout?: number; + }): { combinedSignal: AbortSignal; cleanup: () => void; }; @@ -1902,6 +1917,7 @@ export const UI_SETTINGS: { readonly COURIER_MAX_CONCURRENT_SHARD_REQUESTS: "courier:maxConcurrentShardRequests"; readonly COURIER_BATCH_SEARCHES: "courier:batchSearches"; readonly SEARCH_INCLUDE_FROZEN: "search:includeFrozen"; + readonly SEARCH_TIMEOUT: "search:timeout"; readonly HISTOGRAM_BAR_TARGET: "histogram:barTarget"; readonly HISTOGRAM_MAX_BARS: "histogram:maxBars"; readonly HISTORY_LIMIT: "history:limit"; diff --git a/src/plugins/data/public/search/fetch/get_search_params.test.ts b/src/plugins/data/public/search/fetch/get_search_params.test.ts index 1ecb879b1602..5e83e1f57bb6 100644 --- a/src/plugins/data/public/search/fetch/get_search_params.test.ts +++ b/src/plugins/data/public/search/fetch/get_search_params.test.ts @@ -25,44 +25,12 @@ function getConfigStub(config: any = {}): GetConfigFn { } describe('getSearchParams', () => { - test('includes rest_total_hits_as_int', () => { - const config = getConfigStub(); + test('includes custom preference', () => { + const config = getConfigStub({ + [UI_SETTINGS.COURIER_SET_REQUEST_PREFERENCE]: 'custom', + [UI_SETTINGS.COURIER_CUSTOM_REQUEST_PREFERENCE]: 'aaa', + }); const searchParams = getSearchParams(config); - expect(searchParams.rest_total_hits_as_int).toBe(true); - }); - - test('includes ignore_unavailable', () => { - const config = getConfigStub(); - const searchParams = getSearchParams(config); - expect(searchParams.ignore_unavailable).toBe(true); - }); - - test('includes ignore_throttled according to search:includeFrozen', () => { - let config = getConfigStub({ [UI_SETTINGS.SEARCH_INCLUDE_FROZEN]: true }); - let searchParams = getSearchParams(config); - expect(searchParams.ignore_throttled).toBe(false); - - config = getConfigStub({ [UI_SETTINGS.SEARCH_INCLUDE_FROZEN]: false }); - searchParams = getSearchParams(config); - expect(searchParams.ignore_throttled).toBe(true); - }); - - test('includes max_concurrent_shard_requests according to courier:maxConcurrentShardRequests', () => { - let config = getConfigStub({ [UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS]: 0 }); - let searchParams = getSearchParams(config); - expect(searchParams.max_concurrent_shard_requests).toBe(undefined); - - config = getConfigStub({ [UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS]: 5 }); - searchParams = getSearchParams(config); - expect(searchParams.max_concurrent_shard_requests).toBe(5); - }); - - test('includes timeout according to esShardTimeout if greater than 0', () => { - const config = getConfigStub(); - let searchParams = getSearchParams(config, 0); - expect(searchParams.timeout).toBe(undefined); - - searchParams = getSearchParams(config, 100); - expect(searchParams.timeout).toBe('100ms'); + expect(searchParams.preference).toBe('aaa'); }); }); diff --git a/src/plugins/data/public/search/fetch/get_search_params.ts b/src/plugins/data/public/search/fetch/get_search_params.ts index 5e0395189f64..ed87c4813951 100644 --- a/src/plugins/data/public/search/fetch/get_search_params.ts +++ b/src/plugins/data/public/search/fetch/get_search_params.ts @@ -22,26 +22,12 @@ import { SearchRequest } from './types'; const sessionId = Date.now(); -export function getSearchParams(getConfig: GetConfigFn, esShardTimeout: number = 0) { +export function getSearchParams(getConfig: GetConfigFn) { return { - rest_total_hits_as_int: true, - ignore_unavailable: true, - ignore_throttled: getIgnoreThrottled(getConfig), - max_concurrent_shard_requests: getMaxConcurrentShardRequests(getConfig), preference: getPreference(getConfig), - timeout: getTimeout(esShardTimeout), }; } -export function getIgnoreThrottled(getConfig: GetConfigFn) { - return !getConfig(UI_SETTINGS.SEARCH_INCLUDE_FROZEN); -} - -export function getMaxConcurrentShardRequests(getConfig: GetConfigFn) { - const maxConcurrentShardRequests = getConfig(UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS); - return maxConcurrentShardRequests > 0 ? maxConcurrentShardRequests : undefined; -} - export function getPreference(getConfig: GetConfigFn) { const setRequestPreference = getConfig(UI_SETTINGS.COURIER_SET_REQUEST_PREFERENCE); if (setRequestPreference === 'sessionId') return sessionId; @@ -50,19 +36,15 @@ export function getPreference(getConfig: GetConfigFn) { : undefined; } -export function getTimeout(esShardTimeout: number) { - return esShardTimeout > 0 ? `${esShardTimeout}ms` : undefined; -} - /** @public */ // TODO: Could provide this on runtime contract with dependencies // already wired up. export function getSearchParamsFromRequest( searchRequest: SearchRequest, - dependencies: { esShardTimeout: number; getConfig: GetConfigFn } + dependencies: { getConfig: GetConfigFn } ): ISearchRequestParams { - const { esShardTimeout, getConfig } = dependencies; - const searchParams = getSearchParams(getConfig, esShardTimeout); + const { getConfig } = dependencies; + const searchParams = getSearchParams(getConfig); return { index: searchRequest.index.title || searchRequest.index, diff --git a/src/plugins/data/public/search/fetch/index.ts b/src/plugins/data/public/search/fetch/index.ts index 79cdad1897f9..4b8511edfc26 100644 --- a/src/plugins/data/public/search/fetch/index.ts +++ b/src/plugins/data/public/search/fetch/index.ts @@ -18,14 +18,7 @@ */ export * from './types'; -export { - getSearchParams, - getSearchParamsFromRequest, - getPreference, - getTimeout, - getIgnoreThrottled, - getMaxConcurrentShardRequests, -} from './get_search_params'; +export { getSearchParams, getSearchParamsFromRequest, getPreference } from './get_search_params'; export { RequestFailure } from './request_error'; export { handleResponse } from './handle_response'; diff --git a/src/plugins/data/public/search/legacy/call_client.test.ts b/src/plugins/data/public/search/legacy/call_client.test.ts index 38f3ab200da9..943a02d22088 100644 --- a/src/plugins/data/public/search/legacy/call_client.test.ts +++ b/src/plugins/data/public/search/legacy/call_client.test.ts @@ -60,7 +60,6 @@ describe('callClient', () => { http: coreMock.createStart().http, legacySearchService: {}, config: { get: jest.fn() }, - esShardTimeout: 0, loadingCount$: new BehaviorSubject(0), } as FetchHandlers; diff --git a/src/plugins/data/public/search/search_interceptor.test.ts b/src/plugins/data/public/search/search_interceptor.test.ts index da60f39b522a..84db69a83a00 100644 --- a/src/plugins/data/public/search/search_interceptor.test.ts +++ b/src/plugins/data/public/search/search_interceptor.test.ts @@ -32,15 +32,12 @@ jest.useFakeTimers(); describe('SearchInterceptor', () => { beforeEach(() => { mockCoreSetup = coreMock.createSetup(); - searchInterceptor = new SearchInterceptor( - { - toasts: mockCoreSetup.notifications.toasts, - startServices: mockCoreSetup.getStartServices(), - uiSettings: mockCoreSetup.uiSettings, - http: mockCoreSetup.http, - }, - 1000 - ); + searchInterceptor = new SearchInterceptor({ + toasts: mockCoreSetup.notifications.toasts, + startServices: mockCoreSetup.getStartServices(), + uiSettings: mockCoreSetup.uiSettings, + http: mockCoreSetup.http, + }); }); describe('search', () => { diff --git a/src/plugins/data/public/search/search_interceptor.ts b/src/plugins/data/public/search/search_interceptor.ts index c6c03267163c..0a6d60afed2f 100644 --- a/src/plugins/data/public/search/search_interceptor.ts +++ b/src/plugins/data/public/search/search_interceptor.ts @@ -18,7 +18,16 @@ */ import { trimEnd } from 'lodash'; -import { BehaviorSubject, throwError, timer, Subscription, defer, from, Observable } from 'rxjs'; +import { + BehaviorSubject, + throwError, + timer, + Subscription, + defer, + from, + Observable, + NEVER, +} from 'rxjs'; import { finalize, filter } from 'rxjs/operators'; import { Toast, CoreStart, ToastsSetup, CoreSetup } from 'kibana/public'; import { getCombinedSignal, AbortError } from '../../common/utils'; @@ -71,17 +80,10 @@ export class SearchInterceptor { */ protected application!: CoreStart['application']; - /** - * This class should be instantiated with a `requestTimeout` corresponding with how many ms after - * requests are initiated that they should automatically cancel. - * @param toasts The `core.notifications.toasts` service - * @param application The `core.application` service - * @param requestTimeout Usually config value `elasticsearch.requestTimeout` + /* + * @internal */ - constructor( - protected readonly deps: SearchInterceptorDeps, - protected readonly requestTimeout?: number - ) { + constructor(protected readonly deps: SearchInterceptorDeps) { this.deps.http.addLoadingCountSource(this.pendingCount$); this.deps.startServices.then(([coreStart]) => { @@ -94,7 +96,6 @@ export class SearchInterceptor { .pipe(filter((count) => count === 0)) .subscribe(this.hideToast); } - /** * Returns an `Observable` over the current number of pending searches. This could mean that one * of the search requests is still in flight, or that it has only received partial responses. @@ -103,6 +104,9 @@ export class SearchInterceptor { return this.pendingCount$.asObservable(); } + /** + * @internal + */ protected runSearch( request: IEsSearchRequest, signal: AbortSignal, @@ -136,7 +140,9 @@ export class SearchInterceptor { return throwError(new AbortError()); } - const { combinedSignal, cleanup } = this.setupTimers(options); + const { combinedSignal, cleanup } = this.setupAbortSignal({ + abortSignal: options?.abortSignal, + }); this.pendingCount$.next(this.pendingCount$.getValue() + 1); return this.runSearch(request, combinedSignal, options?.strategy).pipe( @@ -148,11 +154,20 @@ export class SearchInterceptor { }); } - protected setupTimers(options?: ISearchOptions) { + /** + * @internal + */ + protected setupAbortSignal({ + abortSignal, + timeout, + }: { + abortSignal?: AbortSignal; + timeout?: number; + }) { // Schedule this request to automatically timeout after some interval const timeoutController = new AbortController(); const { signal: timeoutSignal } = timeoutController; - const timeout$ = timer(this.requestTimeout); + const timeout$ = timeout ? timer(timeout) : NEVER; const subscription = timeout$.subscribe(() => { timeoutController.abort(); }); @@ -168,7 +183,7 @@ export class SearchInterceptor { const signals = [ this.abortController.signal, timeoutSignal, - ...(options?.abortSignal ? [options.abortSignal] : []), + ...(abortSignal ? [abortSignal] : []), ]; const combinedSignal = getCombinedSignal(signals); diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index a49d2ef0956f..f8f4acbe43df 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -52,26 +52,19 @@ export class SearchService implements Plugin { { http, getStartServices, injectedMetadata, notifications, uiSettings }: CoreSetup, { expressions, usageCollection }: SearchServiceSetupDependencies ): ISearchSetup { - const esRequestTimeout = injectedMetadata.getInjectedVar('esRequestTimeout') as number; - this.usageCollector = createUsageCollector(getStartServices, usageCollection); /** * A global object that intercepts all searches and provides convenience methods for cancelling * all pending search requests, as well as getting the number of pending search requests. - * TODO: Make this modular so that apps can opt in/out of search collection, or even provide - * their own search collector instances */ - this.searchInterceptor = new SearchInterceptor( - { - toasts: notifications.toasts, - http, - uiSettings, - startServices: getStartServices(), - usageCollector: this.usageCollector!, - }, - esRequestTimeout - ); + this.searchInterceptor = new SearchInterceptor({ + toasts: notifications.toasts, + http, + uiSettings, + startServices: getStartServices(), + usageCollector: this.usageCollector!, + }); expressions.registerFunction(esdsl); expressions.registerType(esRawResponse); @@ -101,8 +94,6 @@ export class SearchService implements Plugin { const searchSourceDependencies: SearchSourceDependencies = { getConfig: uiSettings.get.bind(uiSettings), - // TODO: we don't need this, apply on the server - esShardTimeout: injectedMetadata.getInjectedVar('esShardTimeout') as number, search, http, loadingCount$, diff --git a/src/plugins/data/public/search/search_source/create_search_source.test.ts b/src/plugins/data/public/search/search_source/create_search_source.test.ts index 2820aab67ea3..bc1c7c06c880 100644 --- a/src/plugins/data/public/search/search_source/create_search_source.test.ts +++ b/src/plugins/data/public/search/search_source/create_search_source.test.ts @@ -35,7 +35,6 @@ describe('createSearchSource', () => { dependencies = { getConfig: jest.fn(), search: jest.fn(), - esShardTimeout: 30000, http: coreMock.createStart().http, loadingCount$: new BehaviorSubject(0), }; diff --git a/src/plugins/data/public/search/search_source/mocks.ts b/src/plugins/data/public/search/search_source/mocks.ts index bc3e287d9fe8..adf53bee33fe 100644 --- a/src/plugins/data/public/search/search_source/mocks.ts +++ b/src/plugins/data/public/search/search_source/mocks.ts @@ -53,7 +53,6 @@ export const searchSourceMock = { export const createSearchSourceMock = (fields?: SearchSourceFields) => new SearchSource(fields, { getConfig: uiSettingsServiceMock.createStartContract().get, - esShardTimeout: 30000, search: jest.fn(), http: httpServiceMock.createStartContract(), loadingCount$: new BehaviorSubject(0), diff --git a/src/plugins/data/public/search/search_source/search_source.test.ts b/src/plugins/data/public/search/search_source/search_source.test.ts index a8baed9faa84..282a33e6d01f 100644 --- a/src/plugins/data/public/search/search_source/search_source.test.ts +++ b/src/plugins/data/public/search/search_source/search_source.test.ts @@ -68,7 +68,6 @@ describe('SearchSource', () => { searchSourceDependencies = { getConfig: jest.fn(), search: mockSearchMethod, - esShardTimeout: 30000, http: coreMock.createStart().http, loadingCount$: new BehaviorSubject(0), }; diff --git a/src/plugins/data/public/search/search_source/search_source.ts b/src/plugins/data/public/search/search_source/search_source.ts index eec2d9b50eaf..68c7b663b362 100644 --- a/src/plugins/data/public/search/search_source/search_source.ts +++ b/src/plugins/data/public/search/search_source/search_source.ts @@ -118,7 +118,6 @@ export interface SearchSourceDependencies { getConfig: GetConfigFn; search: ISearchGeneric; http: HttpStart; - esShardTimeout: number; loadingCount$: BehaviorSubject; } @@ -233,10 +232,9 @@ export class SearchSource { * @return {Observable>} */ private fetch$(searchRequest: SearchRequest, options: ISearchOptions) { - const { search, esShardTimeout, getConfig } = this.dependencies; + const { search, getConfig } = this.dependencies; const params = getSearchParamsFromRequest(searchRequest, { - esShardTimeout, getConfig, }); diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 71ed83290e69..03baff491030 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -212,8 +212,11 @@ export { ISearchStrategy, ISearchSetup, ISearchStart, + toSnakeCase, getDefaultSearchParams, + getShardTimeout, getTotalLoaded, + shimHitsTotal, usageProvider, SearchUsage, } from './search'; diff --git a/src/plugins/data/server/search/es_search/es_search_strategy.test.ts b/src/plugins/data/server/search/es_search/es_search_strategy.test.ts index c34c3a310814..504ce728481f 100644 --- a/src/plugins/data/server/search/es_search/es_search_strategy.test.ts +++ b/src/plugins/data/server/search/es_search/es_search_strategy.test.ts @@ -36,7 +36,14 @@ describe('ES search strategy', () => { }, }); const mockContext = { - core: { elasticsearch: { client: { asCurrentUser: { search: mockApiCaller } } } }, + core: { + uiSettings: { + client: { + get: () => {}, + }, + }, + elasticsearch: { client: { asCurrentUser: { search: mockApiCaller } } }, + }, }; const mockConfig$ = pluginInitializerContextConfigMock({}).legacy.globalConfig$; @@ -59,14 +66,13 @@ describe('ES search strategy', () => { expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toEqual({ ...params, - timeout: '0ms', - ignoreUnavailable: true, - restTotalHitsAsInt: true, + ignore_unavailable: true, + track_total_hits: true, }); }); it('calls the API caller with overridden defaults', async () => { - const params = { index: 'logstash-*', ignoreUnavailable: false, timeout: '1000ms' }; + const params = { index: 'logstash-*', ignore_unavailable: false, timeout: '1000ms' }; const esSearch = await esSearchStrategyProvider(mockConfig$, mockLogger); await esSearch.search((mockContext as unknown) as RequestHandlerContext, { params }); @@ -74,7 +80,7 @@ describe('ES search strategy', () => { expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toEqual({ ...params, - restTotalHitsAsInt: true, + track_total_hits: true, }); }); diff --git a/src/plugins/data/server/search/es_search/es_search_strategy.ts b/src/plugins/data/server/search/es_search/es_search_strategy.ts index eabbf3e3e260..106f974ed345 100644 --- a/src/plugins/data/server/search/es_search/es_search_strategy.ts +++ b/src/plugins/data/server/search/es_search/es_search_strategy.ts @@ -22,7 +22,8 @@ import { SearchResponse } from 'elasticsearch'; import { Observable } from 'rxjs'; import { ApiResponse } from '@elastic/elasticsearch'; import { SearchUsage } from '../collectors/usage'; -import { ISearchStrategy, getDefaultSearchParams, getTotalLoaded } from '..'; +import { toSnakeCase } from './to_snake_case'; +import { ISearchStrategy, getDefaultSearchParams, getTotalLoaded, getShardTimeout } from '..'; export const esSearchStrategyProvider = ( config$: Observable, @@ -33,7 +34,7 @@ export const esSearchStrategyProvider = ( search: async (context, request, options) => { logger.debug(`search ${request.params?.index}`); const config = await config$.pipe(first()).toPromise(); - const defaultParams = getDefaultSearchParams(config); + const uiSettingsClient = await context.core.uiSettings.client; // Only default index pattern type is supported here. // See data_enhanced for other type support. @@ -41,10 +42,14 @@ export const esSearchStrategyProvider = ( throw new Error(`Unsupported index pattern type ${request.indexType}`); } - const params = { + // ignoreThrottled is not supported in OSS + const { ignoreThrottled, ...defaultParams } = await getDefaultSearchParams(uiSettingsClient); + + const params = toSnakeCase({ ...defaultParams, + ...getShardTimeout(config), ...request.params, - }; + }); try { const esResponse = (await context.core.elasticsearch.client.asCurrentUser.search( diff --git a/src/plugins/data/server/search/es_search/get_default_search_params.ts b/src/plugins/data/server/search/es_search/get_default_search_params.ts index b2341ccc0f3c..13607fce5167 100644 --- a/src/plugins/data/server/search/es_search/get_default_search_params.ts +++ b/src/plugins/data/server/search/es_search/get_default_search_params.ts @@ -17,12 +17,28 @@ * under the License. */ -import { SharedGlobalConfig } from '../../../../../core/server'; +import { SharedGlobalConfig, IUiSettingsClient } from '../../../../../core/server'; +import { UI_SETTINGS } from '../../../common/constants'; -export function getDefaultSearchParams(config: SharedGlobalConfig) { +export function getShardTimeout(config: SharedGlobalConfig) { + const timeout = config.elasticsearch.shardTimeout.asMilliseconds(); + return timeout + ? { + timeout: `${timeout}ms`, + } + : {}; +} + +export async function getDefaultSearchParams(uiSettingsClient: IUiSettingsClient) { + const ignoreThrottled = !(await uiSettingsClient.get(UI_SETTINGS.SEARCH_INCLUDE_FROZEN)); + const maxConcurrentShardRequests = await uiSettingsClient.get( + UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS + ); return { - timeout: `${config.elasticsearch.shardTimeout.asMilliseconds()}ms`, + maxConcurrentShardRequests: + maxConcurrentShardRequests > 0 ? maxConcurrentShardRequests : undefined, + ignoreThrottled, ignoreUnavailable: true, // Don't fail if the index/indices don't exist - restTotalHitsAsInt: true, // Get the number of hits as an int rather than a range + trackTotalHits: true, }; } diff --git a/src/plugins/data/server/search/es_search/index.ts b/src/plugins/data/server/search/es_search/index.ts index 20006b70730d..1bd17fc98616 100644 --- a/src/plugins/data/server/search/es_search/index.ts +++ b/src/plugins/data/server/search/es_search/index.ts @@ -17,7 +17,9 @@ * under the License. */ -export { ES_SEARCH_STRATEGY, IEsSearchRequest, IEsSearchResponse } from '../../../common/search'; export { esSearchStrategyProvider } from './es_search_strategy'; -export { getDefaultSearchParams } from './get_default_search_params'; +export * from './get_default_search_params'; export { getTotalLoaded } from './get_total_loaded'; +export * from './to_snake_case'; + +export { ES_SEARCH_STRATEGY, IEsSearchRequest, IEsSearchResponse } from '../../../common'; diff --git a/src/legacy/utils/path_contains.js b/src/plugins/data/server/search/es_search/to_snake_case.ts similarity index 83% rename from src/legacy/utils/path_contains.js rename to src/plugins/data/server/search/es_search/to_snake_case.ts index 60d05c109955..74f156274cbc 100644 --- a/src/legacy/utils/path_contains.js +++ b/src/plugins/data/server/search/es_search/to_snake_case.ts @@ -17,8 +17,8 @@ * under the License. */ -import { relative } from 'path'; +import { mapKeys, snakeCase } from 'lodash'; -export default function pathContains(root, child) { - return relative(child, root).slice(0, 2) !== '..'; +export function toSnakeCase(obj: Record) { + return mapKeys(obj, (value, key) => snakeCase(key)); } diff --git a/src/plugins/data/server/search/index.ts b/src/plugins/data/server/search/index.ts index 8a74c51f52f5..b671ed806510 100644 --- a/src/plugins/data/server/search/index.ts +++ b/src/plugins/data/server/search/index.ts @@ -19,8 +19,10 @@ export { ISearchStrategy, ISearchSetup, ISearchStart, SearchEnhancements } from './types'; -export { getDefaultSearchParams, getTotalLoaded } from './es_search'; +export * from './es_search'; export { usageProvider, SearchUsage } from './collectors'; export * from './aggs'; + +export { shimHitsTotal } from './routes'; diff --git a/src/plugins/data/server/search/routes/index.ts b/src/plugins/data/server/search/routes/index.ts index 2217890ff778..a290f08f9b84 100644 --- a/src/plugins/data/server/search/routes/index.ts +++ b/src/plugins/data/server/search/routes/index.ts @@ -19,3 +19,4 @@ export * from './msearch'; export * from './search'; +export * from './shim_hits_total'; diff --git a/src/plugins/data/server/search/routes/msearch.test.ts b/src/plugins/data/server/search/routes/msearch.test.ts index 0a52cf23c547..3a7d67c31b8b 100644 --- a/src/plugins/data/server/search/routes/msearch.test.ts +++ b/src/plugins/data/server/search/routes/msearch.test.ts @@ -48,7 +48,7 @@ describe('msearch route', () => { }); it('handler calls /_msearch with the given request', async () => { - const response = { id: 'yay' }; + const response = { id: 'yay', body: { responses: [{ hits: { total: 5 } }] } }; const mockClient = { transport: { request: jest.fn().mockResolvedValue(response) } }; const mockContext = { core: { @@ -73,7 +73,7 @@ describe('msearch route', () => { expect(mockClient.transport.request.mock.calls[0][0].method).toBe('GET'); expect(mockClient.transport.request.mock.calls[0][0].path).toBe('/_msearch'); expect(mockClient.transport.request.mock.calls[0][0].body).toEqual( - convertRequestBody(mockBody as any, { timeout: '0ms' }) + convertRequestBody(mockBody as any, {}) ); expect(mockResponse.ok).toBeCalled(); expect(mockResponse.ok.mock.calls[0][0]).toEqual({ diff --git a/src/plugins/data/server/search/routes/msearch.ts b/src/plugins/data/server/search/routes/msearch.ts index efb40edd90d5..e1ddb06e4fb6 100644 --- a/src/plugins/data/server/search/routes/msearch.ts +++ b/src/plugins/data/server/search/routes/msearch.ts @@ -20,10 +20,11 @@ import { first } from 'rxjs/operators'; import { schema } from '@kbn/config-schema'; +import { SearchResponse } from 'elasticsearch'; import { IRouter } from 'src/core/server'; -import { UI_SETTINGS } from '../../../common'; import { SearchRouteDependencies } from '../search_service'; -import { getDefaultSearchParams } from '..'; +import { shimHitsTotal } from './shim_hits_total'; +import { getShardTimeout, getDefaultSearchParams, toSnakeCase } from '..'; interface MsearchHeaders { index: string; @@ -96,30 +97,31 @@ export function registerMsearchRoute(router: IRouter, deps: SearchRouteDependenc // get shardTimeout const config = await deps.globalConfig$.pipe(first()).toPromise(); - const { timeout } = getDefaultSearchParams(config); + const timeout = getShardTimeout(config); - const body = convertRequestBody(request.body, { timeout }); + const body = convertRequestBody(request.body, timeout); + + // trackTotalHits is not supported by msearch + const { trackTotalHits, ...defaultParams } = await getDefaultSearchParams( + context.core.uiSettings.client + ); try { - const ignoreThrottled = !(await context.core.uiSettings.client.get( - UI_SETTINGS.SEARCH_INCLUDE_FROZEN - )); - const maxConcurrentShardRequests = await context.core.uiSettings.client.get( - UI_SETTINGS.COURIER_MAX_CONCURRENT_SHARD_REQUESTS - ); const response = await client.transport.request({ method: 'GET', path: '/_msearch', body, - querystring: { - rest_total_hits_as_int: true, - ignore_throttled: ignoreThrottled, - max_concurrent_shard_requests: - maxConcurrentShardRequests > 0 ? maxConcurrentShardRequests : undefined, - }, + querystring: toSnakeCase(defaultParams), }); - return res.ok({ body: response }); + return res.ok({ + body: { + ...response, + body: { + responses: response.body.responses?.map((r: SearchResponse) => shimHitsTotal(r)), + }, + }, + }); } catch (err) { return res.customError({ statusCode: err.statusCode || 500, diff --git a/src/plugins/data/server/search/routes/search.ts b/src/plugins/data/server/search/routes/search.ts index 434028558348..b5d5ec283767 100644 --- a/src/plugins/data/server/search/routes/search.ts +++ b/src/plugins/data/server/search/routes/search.ts @@ -21,6 +21,8 @@ import { schema } from '@kbn/config-schema'; import { IRouter } from 'src/core/server'; import { getRequestAbortedSignal } from '../../lib'; import { SearchRouteDependencies } from '../search_service'; +import { shimHitsTotal } from './shim_hits_total'; +import { isEsResponse } from '../../../common'; export function registerSearchRoute( router: IRouter, @@ -56,7 +58,17 @@ export function registerSearchRoute( strategy, } ); - return res.ok({ body: response }); + + return res.ok({ + body: { + ...response, + ...(isEsResponse(response) + ? { + rawResponse: shimHitsTotal(response.rawResponse), + } + : {}), + }, + }); } catch (err) { return res.customError({ statusCode: err.statusCode || 500, diff --git a/x-pack/plugins/data_enhanced/server/search/shim_hits_total.test.ts b/src/plugins/data/server/search/routes/shim_hits_total.test.ts similarity index 54% rename from x-pack/plugins/data_enhanced/server/search/shim_hits_total.test.ts rename to src/plugins/data/server/search/routes/shim_hits_total.test.ts index 61740b97299d..0f2473538612 100644 --- a/x-pack/plugins/data_enhanced/server/search/shim_hits_total.test.ts +++ b/src/plugins/data/server/search/routes/shim_hits_total.test.ts @@ -1,7 +1,20 @@ /* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ import { shimHitsTotal } from './shim_hits_total'; diff --git a/src/plugins/data/server/search/routes/shim_hits_total.ts b/src/plugins/data/server/search/routes/shim_hits_total.ts new file mode 100644 index 000000000000..5f95b2135897 --- /dev/null +++ b/src/plugins/data/server/search/routes/shim_hits_total.ts @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { SearchResponse } from 'elasticsearch'; + +/** + * Temporary workaround until https://github.com/elastic/kibana/issues/26356 is addressed. + * Since we are setting `track_total_hits` in the request, `hits.total` will be an object + * containing the `value`. + * + * @internal + */ +export function shimHitsTotal(response: SearchResponse) { + const total = (response.hits?.total as any)?.value ?? response.hits?.total; + const hits = { ...response.hits, total }; + return { ...response, hits }; +} diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index a4f5f590e177..cd0369a5c455 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -446,14 +446,25 @@ export interface Filter { query?: any; } -// Warning: (ae-forgotten-export) The symbol "SharedGlobalConfig" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "IUiSettingsClient" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "getDefaultSearchParams" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export function getDefaultSearchParams(config: SharedGlobalConfig): { - timeout: string; +export function getDefaultSearchParams(uiSettingsClient: IUiSettingsClient): Promise<{ + maxConcurrentShardRequests: number | undefined; + ignoreThrottled: boolean; ignoreUnavailable: boolean; - restTotalHitsAsInt: boolean; + trackTotalHits: boolean; +}>; + +// Warning: (ae-forgotten-export) The symbol "SharedGlobalConfig" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "getShardTimeout" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function getShardTimeout(config: SharedGlobalConfig): { + timeout: string; +} | { + timeout?: undefined; }; // Warning: (ae-missing-release-tag) "getTime" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -873,7 +884,7 @@ export class Plugin implements Plugin_2>; + search: ISearchStart>; fieldFormats: { fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; @@ -989,6 +1000,33 @@ export interface SearchUsage { trackSuccess(duration: number): Promise; } +// @internal +export function shimHitsTotal(response: SearchResponse): { + hits: { + total: any; + max_score: number; + hits: { + _index: string; + _type: string; + _id: string; + _score: number; + _source: any; + _version?: number | undefined; + _explanation?: import("elasticsearch").Explanation | undefined; + fields?: any; + highlight?: any; + inner_hits?: any; + matched_queries?: string[] | undefined; + sort?: string[] | undefined; + }[]; + }; + took: number; + timed_out: boolean; + _scroll_id?: string | undefined; + _shards: import("elasticsearch").ShardsResponse; + aggregations?: any; +}; + // Warning: (ae-missing-release-tag) "shouldReadFieldFromDocValues" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -1027,6 +1065,11 @@ export interface TimeRange { to: string; } +// Warning: (ae-missing-release-tag) "toSnakeCase" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export function toSnakeCase(obj: Record): import("lodash").Dictionary; + // Warning: (ae-missing-release-tag) "UI_SETTINGS" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -1043,6 +1086,7 @@ export const UI_SETTINGS: { readonly COURIER_MAX_CONCURRENT_SHARD_REQUESTS: "courier:maxConcurrentShardRequests"; readonly COURIER_BATCH_SEARCHES: "courier:batchSearches"; readonly SEARCH_INCLUDE_FROZEN: "search:includeFrozen"; + readonly SEARCH_TIMEOUT: "search:timeout"; readonly HISTOGRAM_BAR_TARGET: "histogram:barTarget"; readonly HISTOGRAM_MAX_BARS: "histogram:maxBars"; readonly HISTORY_LIMIT: "history:limit"; @@ -1091,19 +1135,19 @@ export function usageProvider(core: CoreSetup_2): SearchUsage; // src/plugins/data/server/index.ts:101:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:127:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:127:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:222:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:222:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:222:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:222:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:224:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:225:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:234:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:235:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:236:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:240:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:241:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:245:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:248:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:225:20 - (ae-forgotten-export) The symbol "getRequestInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:225:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:225:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:225:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:227:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:228:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:237:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:238:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:239:1 - (ae-forgotten-export) The symbol "Ipv4Address" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:243:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:244:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:248:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:251:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/server/plugin.ts:88:66 - (ae-forgotten-export) The symbol "DataEnhancements" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/src/plugins/es_ui_shared/public/request/use_request.test.helpers.tsx b/src/plugins/es_ui_shared/public/request/use_request.test.helpers.tsx index 0d6fd122ad22..7a42ed7fad42 100644 --- a/src/plugins/es_ui_shared/public/request/use_request.test.helpers.tsx +++ b/src/plugins/es_ui_shared/public/request/use_request.test.helpers.tsx @@ -106,7 +106,7 @@ export const createUseRequestHelpers = (): UseRequestHelpers => { }; const TestComponent = ({ requestConfig }: { requestConfig: UseRequestConfig }) => { - const { isInitialRequest, isLoading, error, data, sendRequest } = useRequest( + const { isInitialRequest, isLoading, error, data, resendRequest } = useRequest( httpClient as HttpSetup, requestConfig ); @@ -115,7 +115,7 @@ export const createUseRequestHelpers = (): UseRequestHelpers => { hookResult.isLoading = isLoading; hookResult.error = error; hookResult.data = data; - hookResult.sendRequest = sendRequest; + hookResult.resendRequest = resendRequest; return null; }; diff --git a/src/plugins/es_ui_shared/public/request/use_request.test.ts b/src/plugins/es_ui_shared/public/request/use_request.test.ts index f7902218d931..2a639f93b47b 100644 --- a/src/plugins/es_ui_shared/public/request/use_request.test.ts +++ b/src/plugins/es_ui_shared/public/request/use_request.test.ts @@ -102,7 +102,7 @@ describe('useRequest hook', () => { setupSuccessRequest(); expect(hookResult.isInitialRequest).toBe(true); - hookResult.sendRequest(); + hookResult.resendRequest(); await completeRequest(); expect(hookResult.isInitialRequest).toBe(false); }); @@ -148,7 +148,7 @@ describe('useRequest hook', () => { expect(hookResult.error).toBe(getErrorResponse().error); act(() => { - hookResult.sendRequest(); + hookResult.resendRequest(); }); expect(hookResult.isLoading).toBe(true); expect(hookResult.error).toBe(getErrorResponse().error); @@ -183,7 +183,7 @@ describe('useRequest hook', () => { expect(hookResult.data).toBe(getSuccessResponse().data); act(() => { - hookResult.sendRequest(); + hookResult.resendRequest(); }); expect(hookResult.isLoading).toBe(true); expect(hookResult.data).toBe(getSuccessResponse().data); @@ -215,7 +215,7 @@ describe('useRequest hook', () => { }); describe('callbacks', () => { - describe('sendRequest', () => { + describe('resendRequest', () => { it('sends the request', async () => { const { setupSuccessRequest, completeRequest, hookResult, getSendRequestSpy } = helpers; setupSuccessRequest(); @@ -224,7 +224,7 @@ describe('useRequest hook', () => { expect(getSendRequestSpy().callCount).toBe(1); await act(async () => { - hookResult.sendRequest(); + hookResult.resendRequest(); await completeRequest(); }); expect(getSendRequestSpy().callCount).toBe(2); @@ -239,17 +239,17 @@ describe('useRequest hook', () => { await advanceTime(REQUEST_TIME); expect(getSendRequestSpy().callCount).toBe(1); act(() => { - hookResult.sendRequest(); + hookResult.resendRequest(); }); // The manual request resolves, and we'll send yet another one... await advanceTime(REQUEST_TIME); expect(getSendRequestSpy().callCount).toBe(2); act(() => { - hookResult.sendRequest(); + hookResult.resendRequest(); }); - // At this point, we've moved forward 3s. The poll is set at 2s. If sendRequest didn't + // At this point, we've moved forward 3s. The poll is set at 2s. If resendRequest didn't // reset the poll, the request call count would be 4, not 3. await advanceTime(REQUEST_TIME); expect(getSendRequestSpy().callCount).toBe(3); @@ -291,14 +291,14 @@ describe('useRequest hook', () => { const HALF_REQUEST_TIME = REQUEST_TIME * 0.5; setupSuccessRequest({ pollIntervalMs: REQUEST_TIME }); - // Before the original request resolves, we make a manual sendRequest call. + // Before the original request resolves, we make a manual resendRequest call. await advanceTime(HALF_REQUEST_TIME); expect(getSendRequestSpy().callCount).toBe(0); act(() => { - hookResult.sendRequest(); + hookResult.resendRequest(); }); - // The original quest resolves but it's been marked as outdated by the the manual sendRequest + // The original quest resolves but it's been marked as outdated by the the manual resendRequest // call "interrupts", so data is left undefined. await advanceTime(HALF_REQUEST_TIME); expect(getSendRequestSpy().callCount).toBe(1); diff --git a/src/plugins/es_ui_shared/public/request/use_request.ts b/src/plugins/es_ui_shared/public/request/use_request.ts index 481843bf40e8..e04f84a67b8a 100644 --- a/src/plugins/es_ui_shared/public/request/use_request.ts +++ b/src/plugins/es_ui_shared/public/request/use_request.ts @@ -20,11 +20,7 @@ import { useEffect, useCallback, useState, useRef, useMemo } from 'react'; import { HttpSetup } from '../../../../../src/core/public'; -import { - sendRequest as sendStatelessRequest, - SendRequestConfig, - SendRequestResponse, -} from './send_request'; +import { sendRequest, SendRequestConfig } from './send_request'; export interface UseRequestConfig extends SendRequestConfig { pollIntervalMs?: number; @@ -37,7 +33,7 @@ export interface UseRequestResponse { isLoading: boolean; error: E | null; data?: D | null; - sendRequest: () => Promise>; + resendRequest: () => void; } export const useRequest = ( @@ -80,7 +76,7 @@ export const useRequest = ( /* eslint-disable-next-line react-hooks/exhaustive-deps */ }, [path, method, queryStringified, bodyStringified]); - const sendRequest = useCallback(async () => { + const resendRequest = useCallback(async () => { // If we're on an interval, this allows us to reset it if the user has manually requested the // data, to avoid doubled-up requests. clearPollInterval(); @@ -91,7 +87,7 @@ export const useRequest = ( // "old" error/data or loading state when a new request is in-flight. setIsLoading(true); - const response = await sendStatelessRequest(httpClient, requestBody); + const response = await sendRequest(httpClient, requestBody); const { data: serializedResponseData, error: responseError } = response; const isOutdatedRequest = requestId !== requestCountRef.current; @@ -99,7 +95,7 @@ export const useRequest = ( // Ignore outdated or irrelevant data. if (isOutdatedRequest || isUnmounted) { - return { data: null, error: null }; + return; } setError(responseError); @@ -112,8 +108,6 @@ export const useRequest = ( } // Setting isLoading to false also acts as a signal for scheduling the next poll request. setIsLoading(false); - - return { data: serializedResponseData, error: responseError }; }, [requestBody, httpClient, deserializer, clearPollInterval]); const scheduleRequest = useCallback(() => { @@ -121,19 +115,19 @@ export const useRequest = ( clearPollInterval(); if (pollIntervalMs) { - pollIntervalIdRef.current = setTimeout(sendRequest, pollIntervalMs); + pollIntervalIdRef.current = setTimeout(resendRequest, pollIntervalMs); } - }, [pollIntervalMs, sendRequest, clearPollInterval]); + }, [pollIntervalMs, resendRequest, clearPollInterval]); - // Send the request on component mount and whenever the dependencies of sendRequest() change. + // Send the request on component mount and whenever the dependencies of resendRequest() change. useEffect(() => { - sendRequest(); - }, [sendRequest]); + resendRequest(); + }, [resendRequest]); // Schedule the next poll request when the previous one completes. useEffect(() => { // When a request completes, attempt to schedule the next one. Note that we aren't re-scheduling - // a request whenever sendRequest's dependencies change. isLoading isn't set to false until the + // a request whenever resendRequest's dependencies change. isLoading isn't set to false until the // initial request has completed, so we won't schedule a request on mount. if (!isLoading) { scheduleRequest(); @@ -156,6 +150,6 @@ export const useRequest = ( isLoading, error, data, - sendRequest, // Gives the user the ability to manually request data + resendRequest, // Gives the user the ability to manually request data }; }; diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_array.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_array.ts index 3688421964d2..d0ac0d4ab28c 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_array.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/use_array.ts @@ -17,18 +17,25 @@ * under the License. */ -import { useState, useEffect, useRef, useCallback } from 'react'; +import { useEffect, useRef, useCallback, useMemo } from 'react'; +import { FormHook, FieldConfig } from '../types'; +import { getFieldValidityAndErrorMessage } from '../helpers'; import { useFormContext } from '../form_context'; +import { useField, InternalFieldConfig } from '../hooks'; interface Props { path: string; initialNumberOfItems?: number; readDefaultValueOnForm?: boolean; + validations?: FieldConfig['validations']; children: (args: { items: ArrayItem[]; + error: string | null; addItem: () => void; removeItem: (id: number) => void; + moveItem: (sourceIdx: number, destinationIdx: number) => void; + form: FormHook; }) => JSX.Element; } @@ -56,32 +63,62 @@ export interface ArrayItem { export const UseArray = ({ path, initialNumberOfItems, + validations, readDefaultValueOnForm = true, children, }: Props) => { - const didMountRef = useRef(false); - const form = useFormContext(); - const defaultValues = readDefaultValueOnForm && (form.getFieldDefaultValue(path) as any[]); + const isMounted = useRef(false); const uniqueId = useRef(0); - const getInitialItemsFromValues = (values: any[]): ArrayItem[] => - values.map((_, index) => ({ + const form = useFormContext(); + const { getFieldDefaultValue } = form; + + const getNewItemAtIndex = useCallback( + (index: number): ArrayItem => ({ id: uniqueId.current++, path: `${path}[${index}]`, - isNew: false, - })); + isNew: true, + }), + [path] + ); + + const fieldDefaultValue = useMemo(() => { + const defaultValues = readDefaultValueOnForm + ? (getFieldDefaultValue(path) as any[]) + : undefined; - const getNewItemAtIndex = (index: number): ArrayItem => ({ - id: uniqueId.current++, - path: `${path}[${index}]`, - isNew: true, - }); + const getInitialItemsFromValues = (values: any[]): ArrayItem[] => + values.map((_, index) => ({ + id: uniqueId.current++, + path: `${path}[${index}]`, + isNew: false, + })); - const initialState = defaultValues - ? getInitialItemsFromValues(defaultValues) - : new Array(initialNumberOfItems).fill('').map((_, i) => getNewItemAtIndex(i)); + return defaultValues + ? getInitialItemsFromValues(defaultValues) + : new Array(initialNumberOfItems).fill('').map((_, i) => getNewItemAtIndex(i)); + }, [path, initialNumberOfItems, readDefaultValueOnForm, getFieldDefaultValue, getNewItemAtIndex]); - const [items, setItems] = useState(initialState); + // Create a new hook field with the "hasValue" set to false so we don't use its value to build the final form data. + // Apart from that the field behaves like a normal field and is hooked into the form validation lifecycle. + const fieldConfigBase: FieldConfig & InternalFieldConfig = { + defaultValue: fieldDefaultValue, + errorDisplayDelay: 0, + isIncludedInOutput: false, + }; + + const fieldConfig: FieldConfig & InternalFieldConfig = validations + ? { validations, ...fieldConfigBase } + : fieldConfigBase; + + const field = useField(form, path, fieldConfig); + const { setValue, value, isChangingValue, errors } = field; + + // Derived state from the field + const error = useMemo(() => { + const { errorMessage } = getFieldValidityAndErrorMessage({ isChangingValue, errors }); + return errorMessage; + }, [isChangingValue, errors]); const updatePaths = useCallback( (_rows: ArrayItem[]) => { @@ -96,29 +133,51 @@ export const UseArray = ({ [path] ); - const addItem = () => { - setItems((previousItems) => { + const addItem = useCallback(() => { + setValue((previousItems) => { const itemIndex = previousItems.length; return [...previousItems, getNewItemAtIndex(itemIndex)]; }); - }; + }, [setValue, getNewItemAtIndex]); - const removeItem = (id: number) => { - setItems((previousItems) => { - const updatedItems = previousItems.filter((item) => item.id !== id); - return updatePaths(updatedItems); - }); - }; + const removeItem = useCallback( + (id: number) => { + setValue((previousItems) => { + const updatedItems = previousItems.filter((item) => item.id !== id); + return updatePaths(updatedItems); + }); + }, + [setValue, updatePaths] + ); - useEffect(() => { - if (didMountRef.current) { - setItems((prev) => { - return updatePaths(prev); + const moveItem = useCallback( + (sourceIdx: number, destinationIdx: number) => { + setValue((previousItems) => { + const nextItems = [...previousItems]; + const removed = nextItems.splice(sourceIdx, 1)[0]; + nextItems.splice(destinationIdx, 0, removed); + return updatePaths(nextItems); }); - } else { - didMountRef.current = true; + }, + [setValue, updatePaths] + ); + + useEffect(() => { + if (!isMounted.current) { + return; } - }, [path, updatePaths]); - return children({ items, addItem, removeItem }); + setValue((prev) => { + return updatePaths(prev); + }); + }, [path, updatePaths, setValue]); + + useEffect(() => { + isMounted.current = true; + return () => { + isMounted.current = false; + }; + }, []); + + return children({ items: value, error, form, addItem, removeItem, moveItem }); }; diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/helpers.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/helpers.ts index 7ea42f81b43c..a148dc543542 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/helpers.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/helpers.ts @@ -19,9 +19,10 @@ import { FieldHook } from './types'; -export const getFieldValidityAndErrorMessage = ( - field: FieldHook -): { isInvalid: boolean; errorMessage: string | null } => { +export const getFieldValidityAndErrorMessage = (field: { + isChangingValue: FieldHook['isChangingValue']; + errors: FieldHook['errors']; +}): { isInvalid: boolean; errorMessage: string | null } => { const isInvalid = !field.isChangingValue && field.errors.length > 0; const errorMessage = !field.isChangingValue && field.errors.length ? field.errors[0].message : null; diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/index.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/index.ts index 45c11dd6272e..aa9610dd85ae 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/index.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/index.ts @@ -17,6 +17,6 @@ * under the License. */ -export { useField } from './use_field'; +export { useField, InternalFieldConfig } from './use_field'; export { useForm } from './use_form'; export { useFormData } from './use_form_data'; diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts index f01c7226ea4c..bb4aae6eccae 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_field.ts @@ -22,16 +22,22 @@ import { useMemo, useState, useEffect, useRef, useCallback } from 'react'; import { FormHook, FieldHook, FieldConfig, FieldValidateResponse, ValidationError } from '../types'; import { FIELD_TYPES, VALIDATION_TYPES } from '../constants'; +export interface InternalFieldConfig { + initialValue?: T; + isIncludedInOutput?: boolean; +} + export const useField = ( form: FormHook, path: string, - config: FieldConfig & { initialValue?: T } = {}, + config: FieldConfig & InternalFieldConfig = {}, valueChangeListener?: (value: T) => void ) => { const { type = FIELD_TYPES.TEXT, defaultValue = '', // The value to use a fallback mecanism when no initial value is passed initialValue = config.defaultValue ?? '', // The value explicitly passed + isIncludedInOutput = true, label = '', labelAppend = '', helpText = '', @@ -201,7 +207,7 @@ export const useField = ( validationTypeToValidate, }: { formData: any; - value: unknown; + value: T; validationTypeToValidate?: string; }): ValidationError[] | Promise => { if (!validations) { @@ -234,7 +240,7 @@ export const useField = ( } inflightValidation.current = validator({ - value: (valueToValidate as unknown) as string, + value: valueToValidate, errors: validationErrors, form: { getFormData, getFields }, formData, @@ -280,7 +286,7 @@ export const useField = ( } const validationResult = validator({ - value: (valueToValidate as unknown) as string, + value: valueToValidate, errors: validationErrors, form: { getFormData, getFields }, formData, @@ -388,9 +394,15 @@ export const useField = ( */ const setValue: FieldHook['setValue'] = useCallback( (newValue) => { - const formattedValue = formatInputValue(newValue); - setStateValue(formattedValue); - return formattedValue; + setStateValue((prev) => { + let formattedValue: T; + if (typeof newValue === 'function') { + formattedValue = formatInputValue((newValue as Function)(prev)); + } else { + formattedValue = formatInputValue(newValue); + } + return formattedValue; + }); }, [formatInputValue] ); @@ -496,6 +508,7 @@ export const useField = ( clearErrors, validate, reset, + __isIncludedInOutput: isIncludedInOutput, __serializeValue: serializeValue, }; }, [ @@ -511,6 +524,7 @@ export const useField = ( isValidating, isValidated, isChangingValue, + isIncludedInOutput, onChange, getErrorsMessages, setValue, diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.ts index 7b72a9eeacf7..b390c17d3c2f 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/hooks/use_form.ts @@ -95,19 +95,25 @@ export function useForm( const fieldsToArray = useCallback(() => Object.values(fieldsRefs.current), []); - const stripEmptyFields = useCallback( - (fields: FieldsMap): FieldsMap => { - if (formOptions.stripEmptyFields) { - return Object.entries(fields).reduce((acc, [key, field]) => { - if (typeof field.value !== 'string' || field.value.trim() !== '') { - acc[key] = field; - } + const getFieldsForOutput = useCallback( + (fields: FieldsMap, opts: { stripEmptyFields: boolean }): FieldsMap => { + return Object.entries(fields).reduce((acc, [key, field]) => { + if (!field.__isIncludedInOutput) { return acc; - }, {} as FieldsMap); - } - return fields; + } + + if (opts.stripEmptyFields) { + const isFieldEmpty = typeof field.value === 'string' && field.value.trim() === ''; + if (isFieldEmpty) { + return acc; + } + } + + acc[key] = field; + return acc; + }, {} as FieldsMap); }, - [formOptions] + [] ); const updateFormDataAt: FormHook['__updateFormDataAt'] = useCallback( @@ -133,8 +139,10 @@ export function useForm( const getFormData: FormHook['getFormData'] = useCallback( (getDataOptions: Parameters['getFormData']>[0] = { unflatten: true }) => { if (getDataOptions.unflatten) { - const nonEmptyFields = stripEmptyFields(fieldsRefs.current); - const fieldsValue = mapFormFields(nonEmptyFields, (field) => field.__serializeValue()); + const fieldsToOutput = getFieldsForOutput(fieldsRefs.current, { + stripEmptyFields: formOptions.stripEmptyFields, + }); + const fieldsValue = mapFormFields(fieldsToOutput, (field) => field.__serializeValue()); return serializer ? (serializer(unflattenObject(fieldsValue)) as T) : (unflattenObject(fieldsValue) as T); @@ -148,7 +156,7 @@ export function useForm( {} as T ); }, - [stripEmptyFields, serializer] + [getFieldsForOutput, formOptions.stripEmptyFields, serializer] ); const getErrors: FormHook['getErrors'] = useCallback(() => { diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts b/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts index 4b343ec5e9f2..18b8f478f7c0 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/types.ts @@ -108,15 +108,18 @@ export interface FieldHook { errorCode?: string; }) => string | null; onChange: (event: ChangeEvent<{ name?: string; value: string; checked?: boolean }>) => void; - setValue: (value: T) => T; + setValue: (value: T | ((prevValue: T) => T)) => void; setErrors: (errors: ValidationError[]) => void; clearErrors: (type?: string | string[]) => void; validate: (validateData?: { formData?: any; - value?: unknown; + value?: T; validationType?: string; }) => FieldValidateResponse | Promise; reset: (options?: { resetValue?: boolean; defaultValue?: T }) => unknown | undefined; + // Flag to indicate if the field value will be included in the form data outputted + // when calling form.getFormData(); + __isIncludedInOutput: boolean; __serializeValue: (rawValue?: unknown) => unknown; } @@ -127,7 +130,7 @@ export interface FieldConfig { readonly helpText?: string | ReactNode; readonly type?: HTMLInputElement['type']; readonly defaultValue?: ValueType; - readonly validations?: Array>; + readonly validations?: Array>; readonly formatters?: FormatterFunc[]; readonly deserializer?: SerializerFunc; readonly serializer?: SerializerFunc; @@ -163,8 +166,8 @@ export interface ValidationFuncArg { errors: readonly ValidationError[]; } -export type ValidationFunc = ( - data: ValidationFuncArg +export type ValidationFunc = ( + data: ValidationFuncArg ) => ValidationError | void | undefined | Promise | void | undefined>; export interface FieldValidateResponse { @@ -184,8 +187,8 @@ type FormatterFunc = (value: any, formData: FormData) => unknown; // string | number | boolean | string[] ... type FieldValue = unknown; -export interface ValidationConfig { - validator: ValidationFunc; +export interface ValidationConfig { + validator: ValidationFunc; type?: string; /** * By default all validation are blockers, which means that if they fail, the field is invalid. diff --git a/src/plugins/home/public/application/components/welcome.tsx b/src/plugins/home/public/application/components/welcome.tsx index cacb507009c7..404185de3d2e 100644 --- a/src/plugins/home/public/application/components/welcome.tsx +++ b/src/plugins/home/public/application/components/welcome.tsx @@ -76,7 +76,7 @@ export class Welcome extends React.Component { componentDidMount() { const { telemetry } = this.props; this.services.trackUiMetric(METRIC_TYPE.LOADED, 'welcomeScreenMount'); - if (telemetry) { + if (telemetry?.telemetryService.userCanChangeSettings) { telemetry.telemetryNotifications.setOptedInNoticeSeen(); } document.addEventListener('keydown', this.hideOnEsc); @@ -88,7 +88,7 @@ export class Welcome extends React.Component { private renderTelemetryEnabledOrDisabledText = () => { const { telemetry } = this.props; - if (!telemetry) { + if (!telemetry || !telemetry.telemetryService.userCanChangeSettings) { return null; } diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/create_edit_field/create_edit_field.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/create_edit_field/create_edit_field.tsx index 22bc78ee0538..13be9ca6c9c2 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/create_edit_field/create_edit_field.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/create_edit_field/create_edit_field.tsx @@ -44,7 +44,7 @@ const newFieldPlaceholder = i18n.translate( export const CreateEditField = withRouter( ({ indexPattern, mode, fieldName, history }: CreateEditFieldProps) => { - const { uiSettings, chrome, notifications } = useKibana< + const { uiSettings, chrome, notifications, data } = useKibana< IndexPatternManagmentContext >().services; const spec = @@ -96,6 +96,7 @@ export const CreateEditField = withRouter( indexPattern={indexPattern} spec={spec} services={{ + saveIndexPattern: data.indexPatterns.save.bind(data.indexPatterns), redirectAway, }} /> diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx index a0eecef66ff9..d09836019b0b 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/edit_index_pattern.tsx @@ -234,7 +234,13 @@ export const EditIndexPattern = withRouter( )} - + ); diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/scripted_field_table.test.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/scripted_field_table.test.tsx index ed50317aed6a..84469a7e1fbd 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/scripted_field_table.test.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/scripted_field_table.test.tsx @@ -21,7 +21,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import { ScriptedFieldsTable } from '../scripted_fields_table'; -import { IIndexPattern } from '../../../../../../plugins/data/common/index_patterns'; +import { IIndexPattern, IndexPattern } from '../../../../../../plugins/data/common/index_patterns'; jest.mock('@elastic/eui', () => ({ EuiTitle: 'eui-title', @@ -54,7 +54,7 @@ const helpers = { const getIndexPatternMock = (mockedFields: any = {}) => ({ ...mockedFields } as IIndexPattern); describe('ScriptedFieldsTable', () => { - let indexPattern: IIndexPattern; + let indexPattern: IndexPattern; beforeEach(() => { indexPattern = getIndexPatternMock({ @@ -62,7 +62,7 @@ describe('ScriptedFieldsTable', () => { { name: 'ScriptedField', lang: 'painless', script: 'x++' }, { name: 'JustATest', lang: 'painless', script: 'z++' }, ], - }); + }) as IndexPattern; }); test('should render normally', async () => { @@ -71,6 +71,7 @@ describe('ScriptedFieldsTable', () => { indexPattern={indexPattern} helpers={helpers} painlessDocLink={'painlessDoc'} + saveIndexPattern={async () => {}} /> ); @@ -88,6 +89,7 @@ describe('ScriptedFieldsTable', () => { indexPattern={indexPattern} helpers={helpers} painlessDocLink={'painlessDoc'} + saveIndexPattern={async () => {}} /> ); @@ -105,15 +107,18 @@ describe('ScriptedFieldsTable', () => { test('should filter based on the lang filter', async () => { const component = shallow( [ - { name: 'ScriptedField', lang: 'painless', script: 'x++' }, - { name: 'JustATest', lang: 'painless', script: 'z++' }, - { name: 'Bad', lang: 'somethingElse', script: 'z++' }, - ], - })} + indexPattern={ + getIndexPatternMock({ + getScriptedFields: () => [ + { name: 'ScriptedField', lang: 'painless', script: 'x++' }, + { name: 'JustATest', lang: 'painless', script: 'z++' }, + { name: 'Bad', lang: 'somethingElse', script: 'z++' }, + ], + }) as IndexPattern + } painlessDocLink={'painlessDoc'} helpers={helpers} + saveIndexPattern={async () => {}} /> ); @@ -131,11 +136,14 @@ describe('ScriptedFieldsTable', () => { test('should hide the table if there are no scripted fields', async () => { const component = shallow( [], - })} + indexPattern={ + getIndexPatternMock({ + getScriptedFields: () => [], + }) as IndexPattern + } painlessDocLink={'painlessDoc'} helpers={helpers} + saveIndexPattern={async () => {}} /> ); @@ -153,6 +161,7 @@ describe('ScriptedFieldsTable', () => { indexPattern={indexPattern} helpers={helpers} painlessDocLink={'painlessDoc'} + saveIndexPattern={async () => {}} /> ); @@ -168,12 +177,15 @@ describe('ScriptedFieldsTable', () => { const removeScriptedField = jest.fn(); const component = shallow( {}} /> ); diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/scripted_fields_table.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/scripted_fields_table.tsx index 532af2757915..08cc90faf75f 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/scripted_fields_table.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/scripted_fields_table/scripted_fields_table.tsx @@ -27,10 +27,10 @@ import { import { Table, Header, CallOuts, DeleteScritpedFieldConfirmationModal } from './components'; import { ScriptedFieldItem } from './types'; -import { IIndexPattern } from '../../../../../../plugins/data/public'; +import { IndexPattern, DataPublicPluginStart } from '../../../../../../plugins/data/public'; interface ScriptedFieldsTableProps { - indexPattern: IIndexPattern; + indexPattern: IndexPattern; fieldFilter?: string; scriptedFieldLanguageFilter?: string; helpers: { @@ -39,6 +39,7 @@ interface ScriptedFieldsTableProps { }; onRemoveField?: () => void; painlessDocLink: string; + saveIndexPattern: DataPublicPluginStart['indexPatterns']['save']; } interface ScriptedFieldsTableState { @@ -68,7 +69,7 @@ export class ScriptedFieldsTable extends Component< } fetchFields = async () => { - const fields = await this.props.indexPattern.getScriptedFields(); + const fields = await (this.props.indexPattern.getScriptedFields() as ScriptedFieldItem[]); const deprecatedLangsInUse = []; const deprecatedLangs = getDeprecatedScriptingLanguages(); @@ -121,10 +122,11 @@ export class ScriptedFieldsTable extends Component< }; deleteField = () => { - const { indexPattern, onRemoveField } = this.props; + const { indexPattern, onRemoveField, saveIndexPattern } = this.props; const { fieldToDelete } = this.state; - indexPattern.removeScriptedField(fieldToDelete); + indexPattern.removeScriptedField(fieldToDelete!.name); + saveIndexPattern(indexPattern); if (onRemoveField) { onRemoveField(); diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/__snapshots__/source_filters_table.test.tsx.snap b/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/__snapshots__/source_filters_table.test.tsx.snap index a7b73624c466..6a2b208c4798 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/__snapshots__/source_filters_table.test.tsx.snap +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/__snapshots__/source_filters_table.test.tsx.snap @@ -14,17 +14,6 @@ exports[`SourceFiltersTable should add a filter 1`] = ` fieldWildcardMatcher={[Function]} indexPattern={ Object { - "save": [MockFunction] { - "calls": Array [ - Array [], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, "sourceFilters": Array [ Object { "value": "tim*", @@ -108,17 +97,6 @@ exports[`SourceFiltersTable should remove a filter 1`] = ` fieldWildcardMatcher={[Function]} indexPattern={ Object { - "save": [MockFunction] { - "calls": Array [ - Array [], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, "sourceFilters": Array [ Object { "clientId": 2, @@ -279,17 +257,6 @@ exports[`SourceFiltersTable should update a filter 1`] = ` fieldWildcardMatcher={[Function]} indexPattern={ Object { - "save": [MockFunction] { - "calls": Array [ - Array [], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - }, "sourceFilters": Array [ Object { "clientId": 1, diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/source_filters_table.test.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/source_filters_table.test.tsx index fa048af7c7a7..395e1f3744e9 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/source_filters_table.test.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/source_filters_table.test.tsx @@ -21,7 +21,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import { SourceFiltersTable } from './source_filters_table'; -import { IIndexPattern } from 'src/plugins/data/public'; +import { IndexPattern } from 'src/plugins/data/public'; jest.mock('@elastic/eui', () => ({ EuiButton: 'eui-button', @@ -52,7 +52,7 @@ const getIndexPatternMock = (mockedFields: any = {}) => ({ sourceFilters: [{ value: 'time*' }, { value: 'nam*' }, { value: 'age*' }], ...mockedFields, - } as IIndexPattern); + } as IndexPattern); describe('SourceFiltersTable', () => { test('should render normally', () => { @@ -61,6 +61,7 @@ describe('SourceFiltersTable', () => { indexPattern={getIndexPatternMock()} fieldWildcardMatcher={() => {}} filterFilter={''} + saveIndexPattern={async () => {}} /> ); @@ -73,6 +74,7 @@ describe('SourceFiltersTable', () => { indexPattern={getIndexPatternMock()} fieldWildcardMatcher={() => {}} filterFilter={''} + saveIndexPattern={async () => {}} /> ); @@ -88,6 +90,7 @@ describe('SourceFiltersTable', () => { })} filterFilter={''} fieldWildcardMatcher={() => {}} + saveIndexPattern={async () => {}} /> ); @@ -98,11 +101,14 @@ describe('SourceFiltersTable', () => { test('should show a delete modal', () => { const component = shallow( {}} + saveIndexPattern={async () => {}} /> ); @@ -112,15 +118,17 @@ describe('SourceFiltersTable', () => { }); test('should remove a filter', async () => { - const save = jest.fn(); + const saveIndexPattern = jest.fn(async () => {}); const component = shallow( {}} + saveIndexPattern={saveIndexPattern} /> ); @@ -129,47 +137,49 @@ describe('SourceFiltersTable', () => { await component.instance().deleteFilter(); component.update(); // We are not calling `.setState` directly so we need to re-render - expect(save).toBeCalled(); + expect(saveIndexPattern).toBeCalled(); expect(component).toMatchSnapshot(); }); test('should add a filter', async () => { - const save = jest.fn(); + const saveIndexPattern = jest.fn(async () => {}); const component = shallow( {}} + saveIndexPattern={saveIndexPattern} /> ); await component.instance().onAddFilter('na*'); component.update(); // We are not calling `.setState` directly so we need to re-render - expect(save).toBeCalled(); + expect(saveIndexPattern).toBeCalled(); expect(component).toMatchSnapshot(); }); test('should update a filter', async () => { - const save = jest.fn(); + const saveIndexPattern = jest.fn(async () => {}); const component = shallow( {}} + saveIndexPattern={saveIndexPattern} /> ); await component.instance().saveFilter({ clientId: 'tim*', value: 'ti*' }); component.update(); // We are not calling `.setState` directly so we need to re-render - expect(save).toBeCalled(); + expect(saveIndexPattern).toBeCalled(); expect(component).toMatchSnapshot(); }); }); diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/source_filters_table.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/source_filters_table.tsx index e5c753886ea9..b00648f12471 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/source_filters_table.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/source_filters_table/source_filters_table.tsx @@ -22,14 +22,15 @@ import { createSelector } from 'reselect'; import { EuiSpacer } from '@elastic/eui'; import { AddFilter, Table, Header, DeleteFilterConfirmationModal } from './components'; -import { IIndexPattern } from '../../../../../../plugins/data/public'; +import { IndexPattern, DataPublicPluginStart } from '../../../../../../plugins/data/public'; import { SourceFiltersTableFilter } from './types'; export interface SourceFiltersTableProps { - indexPattern: IIndexPattern; + indexPattern: IndexPattern; filterFilter: string; fieldWildcardMatcher: Function; onAddOrRemoveFilter?: Function; + saveIndexPattern: DataPublicPluginStart['indexPatterns']['save']; } export interface SourceFiltersTableState { @@ -104,7 +105,7 @@ export class SourceFiltersTable extends Component< }; deleteFilter = async () => { - const { indexPattern, onAddOrRemoveFilter } = this.props; + const { indexPattern, onAddOrRemoveFilter, saveIndexPattern } = this.props; const { filterToDelete, filters } = this.state; indexPattern.sourceFilters = filters.filter((filter) => { @@ -112,7 +113,7 @@ export class SourceFiltersTable extends Component< }); this.setState({ isSaving: true }); - await indexPattern.save(); + await saveIndexPattern(indexPattern); if (onAddOrRemoveFilter) { onAddOrRemoveFilter(); @@ -124,12 +125,12 @@ export class SourceFiltersTable extends Component< }; onAddFilter = async (value: string) => { - const { indexPattern, onAddOrRemoveFilter } = this.props; + const { indexPattern, onAddOrRemoveFilter, saveIndexPattern } = this.props; indexPattern.sourceFilters = [...(indexPattern.sourceFilters || []), { value }]; this.setState({ isSaving: true }); - await indexPattern.save(); + await saveIndexPattern(indexPattern); if (onAddOrRemoveFilter) { onAddOrRemoveFilter(); @@ -140,7 +141,7 @@ export class SourceFiltersTable extends Component< }; saveFilter = async ({ clientId, value }: SourceFiltersTableFilter) => { - const { indexPattern } = this.props; + const { indexPattern, saveIndexPattern } = this.props; const { filters } = this.state; indexPattern.sourceFilters = filters.map((filter) => { @@ -155,7 +156,7 @@ export class SourceFiltersTable extends Component< }); this.setState({ isSaving: true }); - await indexPattern.save(); + await saveIndexPattern(indexPattern); this.updateFilters(); this.setState({ isSaving: false }); }; diff --git a/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx b/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx index 3bc9cd34f298..101399ef02b7 100644 --- a/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx +++ b/src/plugins/index_pattern_management/public/components/edit_index_pattern/tabs/tabs.tsx @@ -35,6 +35,7 @@ import { IndexPattern, IndexPatternField, UI_SETTINGS, + DataPublicPluginStart, } from '../../../../../../plugins/data/public'; import { useKibana } from '../../../../../../plugins/kibana_react/public'; import { IndexPatternManagmentContext } from '../../../types'; @@ -48,6 +49,7 @@ import { getTabs, getPath, convertToEuiSelectOption } from './utils'; interface TabsProps extends Pick { indexPattern: IndexPattern; fields: IndexPatternField[]; + saveIndexPattern: DataPublicPluginStart['indexPatterns']['save']; } const searchAriaLabel = i18n.translate( @@ -71,7 +73,7 @@ const filterPlaceholder = i18n.translate( } ); -export function Tabs({ indexPattern, fields, history, location }: TabsProps) { +export function Tabs({ indexPattern, saveIndexPattern, fields, history, location }: TabsProps) { const { uiSettings, indexPatternManagementStart, docLinks } = useKibana< IndexPatternManagmentContext >().services; @@ -191,6 +193,7 @@ export function Tabs({ indexPattern, fields, history, location }: TabsProps) { + + + } + onChange={[Function]} + /> + {!(format as DurationFormat).isHuman() ? ( - - } - isInvalid={!!error} - error={hasDecimalError ? error : null} - > - { - this.onChange({ outputPrecision: e.target.value ? Number(e.target.value) : null }); - }} + <> + + } isInvalid={!!error} - /> - + error={hasDecimalError ? error : null} + > + { + this.onChange({ + outputPrecision: e.target.value ? Number(e.target.value) : null, + }); + }} + isInvalid={!!error} + /> + + + + } + checked={Boolean(formatParams.showSuffix)} + onChange={(e) => { + this.onChange({ showSuffix: !formatParams.showSuffix }); + }} + /> + + ) : null} diff --git a/src/plugins/index_pattern_management/public/components/field_editor/field_editor.test.tsx b/src/plugins/index_pattern_management/public/components/field_editor/field_editor.test.tsx index b0385a61a72a..23f52475d413 100644 --- a/src/plugins/index_pattern_management/public/components/field_editor/field_editor.test.tsx +++ b/src/plugins/index_pattern_management/public/components/field_editor/field_editor.test.tsx @@ -94,6 +94,8 @@ const field = { format: new Format(), }; +const services = { redirectAway: () => {}, saveIndexPattern: async () => {} }; + describe('FieldEditor', () => { let indexPattern: IndexPattern; @@ -122,7 +124,7 @@ describe('FieldEditor', () => { { indexPattern, spec: (field as unknown) as IndexPatternField, - services: { redirectAway: () => {} }, + services, }, mockContext ); @@ -151,7 +153,7 @@ describe('FieldEditor', () => { { indexPattern, spec: (testField as unknown) as IndexPatternField, - services: { redirectAway: () => {} }, + services, }, mockContext ); @@ -181,7 +183,7 @@ describe('FieldEditor', () => { { indexPattern, spec: (testField as unknown) as IndexPatternField, - services: { redirectAway: () => {} }, + services, }, mockContext ); @@ -198,7 +200,7 @@ describe('FieldEditor', () => { { indexPattern, spec: (testField as unknown) as IndexPatternField, - services: { redirectAway: () => {} }, + services, }, mockContext ); @@ -223,7 +225,7 @@ describe('FieldEditor', () => { { indexPattern, spec: (testField as unknown) as IndexPatternField, - services: { redirectAway: () => {} }, + services, }, mockContext ); diff --git a/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx b/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx index 6a3f632a9582..4857a402cc4b 100644 --- a/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx +++ b/src/plugins/index_pattern_management/public/components/field_editor/field_editor.tsx @@ -133,6 +133,7 @@ export interface FieldEdiorProps { spec: IndexPatternField['spec']; services: { redirectAway: () => void; + saveIndexPattern: DataPublicPluginStart['indexPatterns']['save']; }; } @@ -757,23 +758,18 @@ export class FieldEditor extends PureComponent { - const { redirectAway } = this.props.services; + const { redirectAway, saveIndexPattern } = this.props.services; const { indexPattern } = this.props; const { spec } = this.state; - const remove = indexPattern.removeScriptedField(spec.name); - - if (remove) { - remove.then(() => { - const message = i18n.translate('indexPatternManagement.deleteField.deletedHeader', { - defaultMessage: "Deleted '{fieldName}'", - values: { fieldName: spec.name }, - }); - this.context.services.notifications.toasts.addSuccess(message); - redirectAway(); + indexPattern.removeScriptedField(spec.name); + saveIndexPattern(indexPattern).then(() => { + const message = i18n.translate('indexPatternManagement.deleteField.deletedHeader', { + defaultMessage: "Deleted '{fieldName}'", + values: { fieldName: spec.name }, }); - } else { + this.context.services.notifications.toasts.addSuccess(message); redirectAway(); - } + }); }; saveField = async () => { @@ -803,7 +799,7 @@ export class FieldEditor extends PureComponent { const message = i18n.translate('indexPatternManagement.deleteField.savedHeader', { defaultMessage: "Saved '{fieldName}'", diff --git a/src/plugins/input_control_vis/public/vis_controller.tsx b/src/plugins/input_control_vis/public/vis_controller.tsx index e4310960851c..faea98b79229 100644 --- a/src/plugins/input_control_vis/public/vis_controller.tsx +++ b/src/plugins/input_control_vis/public/vis_controller.tsx @@ -18,8 +18,10 @@ */ import React from 'react'; +import { isEqual } from 'lodash'; import { render, unmountComponentAtNode } from 'react-dom'; +import { Subscription } from 'rxjs'; import { I18nStart } from 'kibana/public'; import { InputControlVis } from './components/vis/input_control_vis'; import { getControlFactory } from './control/control_factory'; @@ -34,11 +36,13 @@ import { VisParams, Vis } from '../../visualizations/public'; export const createInputControlVisController = (deps: InputControlVisDependencies) => { return class InputControlVisController { private I18nContext?: I18nStart['Context']; + private isLoaded = false; controls: Array; queryBarUpdateHandler: () => void; filterManager: FilterManager; updateSubsciption: any; + timeFilterSubscription: Subscription; visParams?: VisParams; constructor(public el: Element, public vis: Vis) { @@ -50,19 +54,32 @@ export const createInputControlVisController = (deps: InputControlVisDependencie this.updateSubsciption = this.filterManager .getUpdates$() .subscribe(this.queryBarUpdateHandler); + this.timeFilterSubscription = deps.data.query.timefilter.timefilter + .getTimeUpdate$() + .subscribe(() => { + if (this.visParams?.useTimeFilter) { + this.isLoaded = false; + } + }); } async render(visData: any, visParams: VisParams) { - this.visParams = visParams; - this.controls = []; - this.controls = await this.initControls(); - const [{ i18n }] = await deps.core.getStartServices(); - this.I18nContext = i18n.Context; + if (!this.I18nContext) { + const [{ i18n }] = await deps.core.getStartServices(); + this.I18nContext = i18n.Context; + } + if (!this.isLoaded || !isEqual(visParams, this.visParams)) { + this.visParams = visParams; + this.controls = []; + this.controls = await this.initControls(); + this.isLoaded = true; + } this.drawVis(); } destroy() { this.updateSubsciption.unsubscribe(); + this.timeFilterSubscription.unsubscribe(); unmountComponentAtNode(this.el); this.controls.forEach((control) => control.destroy()); } diff --git a/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts index 6efe87255358..2e79cdaa7fc6 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts @@ -66,6 +66,7 @@ export const applicationUsageSchema = { csm: commonSchema, canvas: commonSchema, dashboard_mode: commonSchema, // It's a forward app so we'll likely never report it + enterpriseSearch: commonSchema, appSearch: commonSchema, workplaceSearch: commonSchema, graph: commonSchema, diff --git a/src/plugins/kibana_usage_collection/server/collectors/ops_stats/index.test.ts b/src/plugins/kibana_usage_collection/server/collectors/ops_stats/index.test.ts index 359d3a396665..a527d4d03c6f 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/ops_stats/index.test.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/ops_stats/index.test.ts @@ -39,6 +39,7 @@ describe('telemetry_ops_stats', () => { const callCluster = jest.fn(); const metric: OpsMetrics = { + collected_at: new Date('2020-01-01 01:00:00'), process: { memory: { heap: { diff --git a/src/plugins/kibana_usage_collection/server/collectors/ops_stats/ops_stats_collector.ts b/src/plugins/kibana_usage_collection/server/collectors/ops_stats/ops_stats_collector.ts index 6e8b71d675f7..d3be60154058 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/ops_stats/ops_stats_collector.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/ops_stats/ops_stats_collector.ts @@ -18,13 +18,13 @@ */ import { Observable } from 'rxjs'; -import { cloneDeep } from 'lodash'; +import { cloneDeep, omit } from 'lodash'; import moment from 'moment'; import { OpsMetrics } from 'kibana/server'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { KIBANA_STATS_TYPE } from '../../../common/constants'; -interface OpsStatsMetrics extends Omit { +interface OpsStatsMetrics extends Omit { timestamp: string; response_times: { average: number; @@ -52,9 +52,9 @@ export function getOpsStatsCollector( // @ts-expect-error delete metrics.requests.statusCodes; lastMetrics = { - ...metrics, + ...omit(metrics, ['collected_at']), response_times: responseTimes, - timestamp: moment.utc().toISOString(), + timestamp: moment.utc(metrics.collected_at).toISOString(), }; }); diff --git a/src/plugins/kibana_usage_collection/server/collectors/ui_metric/index.test.ts b/src/plugins/kibana_usage_collection/server/collectors/ui_metric/index.test.ts index fca685ef4b80..d6f40a2a6867 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/ui_metric/index.test.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/ui_metric/index.test.ts @@ -73,6 +73,11 @@ describe('telemetry_ui_metric', () => { { id: 'testAppName:testKeyName1', attributes: { count: 3 } }, { id: 'testAppName:testKeyName2', attributes: { count: 5 } }, { id: 'testAppName2:testKeyName3', attributes: { count: 1 } }, + { + id: + 'kibana-user_agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:80.0) Gecko/20100101 Firefox/80.0', + attributes: { count: 1 }, + }, ], total: 3, } as any; @@ -86,6 +91,12 @@ describe('telemetry_ui_metric', () => { { key: 'testKeyName2', value: 5 }, ], testAppName2: [{ key: 'testKeyName3', value: 1 }], + 'kibana-user_agent': [ + { + key: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:80.0) Gecko/20100101 Firefox/80.0', + value: 1, + }, + ], }); }); }); diff --git a/src/plugins/kibana_usage_collection/server/collectors/ui_metric/telemetry_ui_metric_collector.ts b/src/plugins/kibana_usage_collection/server/collectors/ui_metric/telemetry_ui_metric_collector.ts index ec2f1bfdfc25..46768813b197 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/ui_metric/telemetry_ui_metric_collector.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/ui_metric/telemetry_ui_metric_collector.ts @@ -66,9 +66,9 @@ export function registerUiMetricUsageCollector( attributes: { count }, } = rawUiMetric; - const [appName, metricType] = id.split(':'); + const [appName, ...metricType] = id.split(':'); - const pair = { key: metricType, value: count }; + const pair = { key: metricType.join(':'), value: count }; return { ...accum, [appName]: [...(accum[appName] || []), pair], diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx index a1a40b49cc8f..b284c60bac5d 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.tsx @@ -23,39 +23,44 @@ import classNames from 'classnames'; import { MountPoint } from '../../../../core/public'; import { MountPointPortal } from '../../../kibana_react/public'; -import { StatefulSearchBarProps, DataPublicPluginStart } from '../../../data/public'; +import { + StatefulSearchBarProps, + DataPublicPluginStart, + SearchBarProps, +} from '../../../data/public'; import { TopNavMenuData } from './top_nav_menu_data'; import { TopNavMenuItem } from './top_nav_menu_item'; -export type TopNavMenuProps = StatefulSearchBarProps & { - config?: TopNavMenuData[]; - showSearchBar?: boolean; - showQueryBar?: boolean; - showQueryInput?: boolean; - showDatePicker?: boolean; - showFilterBar?: boolean; - data?: DataPublicPluginStart; - className?: string; - /** - * If provided, the menu part of the component will be rendered as a portal inside the given mount point. - * - * This is meant to be used with the `setHeaderActionMenu` core API. - * - * @example - * ```ts - * export renderApp = ({ element, history, setHeaderActionMenu }: AppMountParameters) => { - * const topNavConfig = ...; // TopNavMenuProps - * return ( - * - * - * - * - * ) - * } - * ``` - */ - setMenuMountPoint?: (menuMount: MountPoint | undefined) => void; -}; +export type TopNavMenuProps = StatefulSearchBarProps & + Omit & { + config?: TopNavMenuData[]; + showSearchBar?: boolean; + showQueryBar?: boolean; + showQueryInput?: boolean; + showDatePicker?: boolean; + showFilterBar?: boolean; + data?: DataPublicPluginStart; + className?: string; + /** + * If provided, the menu part of the component will be rendered as a portal inside the given mount point. + * + * This is meant to be used with the `setHeaderActionMenu` core API. + * + * @example + * ```ts + * export renderApp = ({ element, history, setHeaderActionMenu }: AppMountParameters) => { + * const topNavConfig = ...; // TopNavMenuProps + * return ( + * + * + * + * + * ) + * } + * ``` + */ + setMenuMountPoint?: (menuMount: MountPoint | undefined) => void; + }; /* * Top Nav Menu is a convenience wrapper component for: diff --git a/src/plugins/saved_objects/public/save_modal/saved_object_save_modal.tsx b/src/plugins/saved_objects/public/save_modal/saved_object_save_modal.tsx index 3b9efbee22ba..9cdef8b9392b 100644 --- a/src/plugins/saved_objects/public/save_modal/saved_object_save_modal.tsx +++ b/src/plugins/saved_objects/public/save_modal/saved_object_save_modal.tsx @@ -294,7 +294,7 @@ export class SavedObjectSaveModal extends React.Component id="savedObjects.saveModal.duplicateTitleDescription" defaultMessage="Saving '{title}' creates a duplicate title." values={{ - title: this.props.title, + title: this.state.title, }} />

diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap index 9ad82723c116..0a330d074fd4 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/flyout.test.tsx.snap @@ -122,6 +122,8 @@ exports[`Flyout conflicts should allow conflict resolution 1`] = ` grow={false} > @@ -420,6 +422,8 @@ exports[`Flyout legacy conflicts should allow conflict resolution 1`] = ` grow={false} > @@ -553,7 +557,7 @@ exports[`Flyout should render import step 1`] = ` hasEmptyLabelSpace={false} label={ @@ -603,6 +607,8 @@ exports[`Flyout should render import step 1`] = ` grow={false} > diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/header.test.tsx.snap b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/header.test.tsx.snap index 642a5030e4ec..038e1aaf2d8f 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/header.test.tsx.snap +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/__snapshots__/header.test.tsx.snap @@ -92,7 +92,7 @@ exports[`Header should render normally 1`] = ` color="subdued" > diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx index 32462e1e2184..cc9d2ed16024 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.test.tsx @@ -267,6 +267,10 @@ describe('Flyout', () => { expect(component.state('status')).toBe('success'); expect(component.find('EuiFlyout ImportSummary')).toMatchSnapshot(); + const cancelButton = await component.find( + 'EuiButtonEmpty[data-test-subj="importSavedObjectsCancelBtn"]' + ); + expect(cancelButton.prop('disabled')).toBe(true); }); }); diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx index eddca18f9e28..47d82077294c 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx @@ -729,7 +729,7 @@ export class Flyout extends Component { label={ } > @@ -756,7 +756,7 @@ export class Flyout extends Component { } renderFooter() { - const { status } = this.state; + const { isLegacyFile, status } = this.state; const { done, close } = this.props; let confirmButton; @@ -773,7 +773,7 @@ export class Flyout extends Component { } else if (this.hasUnmatchedReferences) { confirmButton = ( { } else { confirmButton = ( { return ( - +

diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_mode_control.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_mode_control.tsx index ac8099893d00..4000d620465a 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_mode_control.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_mode_control.tsx @@ -51,8 +51,7 @@ const createNewCopiesDisabled = { tooltip: i18n.translate( 'savedObjectsManagement.objectsTable.importModeControl.createNewCopies.disabledText', { - defaultMessage: - 'Check if each object was previously copied or imported into the destination space.', + defaultMessage: 'Check if objects were previously copied or imported.', } ), }; @@ -64,21 +63,23 @@ const createNewCopiesEnabled = { ), tooltip: i18n.translate( 'savedObjectsManagement.objectsTable.importModeControl.createNewCopies.enabledText', - { defaultMessage: 'All imported objects will be created with new random IDs.' } + { + defaultMessage: 'Use this option to create one or more copies of the object.', + } ), }; const overwriteEnabled = { id: 'overwriteEnabled', label: i18n.translate( 'savedObjectsManagement.objectsTable.importModeControl.overwrite.enabledLabel', - { defaultMessage: 'Automatically try to overwrite conflicts' } + { defaultMessage: 'Automatically overwrite conflicts' } ), }; const overwriteDisabled = { id: 'overwriteDisabled', label: i18n.translate( 'savedObjectsManagement.objectsTable.importModeControl.overwrite.disabledLabel', - { defaultMessage: 'Request action when conflict occurs' } + { defaultMessage: 'Request action on conflict' } ), }; const importOptionsTitle = i18n.translate( diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.test.tsx index ed65131b0fc6..20ac5a903ef2 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.test.tsx @@ -70,7 +70,7 @@ describe('ImportSummary', () => { const wrapper = shallowWithI18nProvider(); expect(findHeader(wrapper).childAt(0).props()).toEqual( - expect.objectContaining({ values: { importCount: 1 } }) + expect.not.objectContaining({ values: expect.anything() }) // no importCount for singular ); const countCreated = findCountCreated(wrapper); expect(countCreated).toHaveLength(1); @@ -90,7 +90,7 @@ describe('ImportSummary', () => { const wrapper = shallowWithI18nProvider(); expect(findHeader(wrapper).childAt(0).props()).toEqual( - expect.objectContaining({ values: { importCount: 1 } }) + expect.not.objectContaining({ values: expect.anything() }) // no importCount for singular ); expect(findCountCreated(wrapper)).toHaveLength(0); const countOverwritten = findCountOverwritten(wrapper); @@ -110,7 +110,7 @@ describe('ImportSummary', () => { const wrapper = shallowWithI18nProvider(); expect(findHeader(wrapper).childAt(0).props()).toEqual( - expect.objectContaining({ values: { importCount: 1 } }) + expect.not.objectContaining({ values: expect.anything() }) // no importCount for singular ); expect(findCountCreated(wrapper)).toHaveLength(0); expect(findCountOverwritten(wrapper)).toHaveLength(0); diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx index 7949f7d18d35..e2ce3c3695b1 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_summary.tsx @@ -141,7 +141,7 @@ const getCountIndicators = (importItems: ImportItem[]) => { ); }; -const getStatusIndicator = ({ outcome, errorMessage }: ImportItem) => { +const getStatusIndicator = ({ outcome, errorMessage = 'Error' }: ImportItem) => { switch (outcome) { case 'created': return ( @@ -168,8 +168,8 @@ const getStatusIndicator = ({ outcome, errorMessage }: ImportItem) => { type={'alert'} color={'danger'} content={i18n.translate('savedObjectsManagement.importSummary.errorOutcomeLabel', { - defaultMessage: 'Error{message}', - values: { message: errorMessage ? `: ${errorMessage}` : '' }, + defaultMessage: '{errorMessage}', + values: { errorMessage }, })} /> ); @@ -194,11 +194,18 @@ export const ImportSummary = ({ failedImports, successfulImports }: ImportSummar } >

- + {importItems.length === 1 ? ( + + ) : ( + + )}

diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/overwrite_modal.test.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/overwrite_modal.test.tsx index c93bc9e5038d..7576b62552aa 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/overwrite_modal.test.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/overwrite_modal.test.tsx @@ -40,7 +40,7 @@ describe('OverwriteModal', () => { const wrapper = shallowWithI18nProvider(); expect(wrapper.find('p').text()).toMatchInlineSnapshot( - `"\\"baz\\" conflicts with an existing object, are you sure you want to overwrite it?"` + `"\\"baz\\" conflicts with an existing object. Overwrite it?"` ); expect(wrapper.find('EuiSuperSelect')).toHaveLength(0); }); @@ -82,7 +82,7 @@ describe('OverwriteModal', () => { const wrapper = shallowWithI18nProvider(); expect(wrapper.find('p').text()).toMatchInlineSnapshot( - `"\\"baz\\" conflicts with multiple existing objects, do you want to overwrite one of them?"` + `"\\"baz\\" conflicts with multiple existing objects. Overwrite one?"` ); expect(wrapper.find('EuiSuperSelect')).toHaveLength(1); }); diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/overwrite_modal.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/overwrite_modal.tsx index dbe95161cbea..bf27d407fbe9 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/overwrite_modal.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/overwrite_modal.tsx @@ -98,15 +98,13 @@ export const OverwriteModal = ({ conflict, onFinish }: OverwriteModalProps) => { const bodyText = error.type === 'conflict' ? i18n.translate('savedObjectsManagement.objectsTable.overwriteModal.body.conflict', { - defaultMessage: - '"{title}" conflicts with an existing object, are you sure you want to overwrite it?', + defaultMessage: '"{title}" conflicts with an existing object. Overwrite it?', values: { title }, }) : i18n.translate( 'savedObjectsManagement.objectsTable.overwriteModal.body.ambiguousConflict', { - defaultMessage: - '"{title}" conflicts with multiple existing objects, do you want to overwrite one of them?', + defaultMessage: '"{title}" conflicts with multiple existing objects. Overwrite one?', values: { title }, } ); diff --git a/src/plugins/telemetry/public/mocks.ts b/src/plugins/telemetry/public/mocks.ts index dd7e5a4cc4ce..5f38b27144d0 100644 --- a/src/plugins/telemetry/public/mocks.ts +++ b/src/plugins/telemetry/public/mocks.ts @@ -48,6 +48,7 @@ export function mockTelemetryService({ banner: true, allowChangingOptInStatus: true, telemetryNotifyUserAboutOptInDefault: true, + userCanChangeSettings: true, ...configOverride, }; diff --git a/src/plugins/telemetry/public/plugin.ts b/src/plugins/telemetry/public/plugin.ts index 3846e7cb96a1..9fefa2ebdd02 100644 --- a/src/plugins/telemetry/public/plugin.ts +++ b/src/plugins/telemetry/public/plugin.ts @@ -25,6 +25,7 @@ import { PluginInitializerContext, SavedObjectsClientContract, SavedObjectsBatchResponse, + ApplicationStart, } from '../../../core/public'; import { TelemetrySender, TelemetryService, TelemetryNotifications } from './services'; @@ -61,6 +62,7 @@ export interface TelemetryPluginConfig { optInStatusUrl: string; sendUsageFrom: 'browser' | 'server'; telemetryNotifyUserAboutOptInDefault?: boolean; + userCanChangeSettings?: boolean; } export class TelemetryPlugin implements Plugin { @@ -69,6 +71,7 @@ export class TelemetryPlugin implements Plugin) { this.currentKibanaVersion = initializerContext.env.packageInfo.version; @@ -91,6 +94,9 @@ export class TelemetryPlugin implements Plugin { expect(telemetryService.setUserHasSeenNotice).toBeCalledTimes(1); }); }); + +describe('shouldShowOptedInNoticeBanner', () => { + it("should return true because a banner hasn't been shown, the notice hasn't been seen and the user has privileges to edit saved objects", () => { + const telemetryService = mockTelemetryService(); + telemetryService.getUserShouldSeeOptInNotice = jest.fn().mockReturnValue(true); + const telemetryNotifications = mockTelemetryNotifications({ telemetryService }); + expect(telemetryNotifications.shouldShowOptedInNoticeBanner()).toBe(true); + }); + + it('should return false because the banner is already on screen', () => { + const telemetryService = mockTelemetryService(); + telemetryService.getUserShouldSeeOptInNotice = jest.fn().mockReturnValue(true); + const telemetryNotifications = mockTelemetryNotifications({ telemetryService }); + telemetryNotifications['optedInNoticeBannerId'] = 'bruce-banner'; + expect(telemetryNotifications.shouldShowOptedInNoticeBanner()).toBe(false); + }); + + it("should return false because the banner has already been seen or the user doesn't have privileges to change saved objects", () => { + const telemetryService = mockTelemetryService(); + telemetryService.getUserShouldSeeOptInNotice = jest.fn().mockReturnValue(false); + const telemetryNotifications = mockTelemetryNotifications({ telemetryService }); + expect(telemetryNotifications.shouldShowOptedInNoticeBanner()).toBe(false); + }); +}); diff --git a/src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts b/src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts index bf25bb592db8..fc44a4db7cf5 100644 --- a/src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts +++ b/src/plugins/telemetry/public/services/telemetry_notifications/telemetry_notifications.ts @@ -39,9 +39,9 @@ export class TelemetryNotifications { } public shouldShowOptedInNoticeBanner = (): boolean => { - const userHasSeenOptedInNotice = this.telemetryService.getUserHasSeenOptedInNotice(); + const userShouldSeeOptInNotice = this.telemetryService.getUserShouldSeeOptInNotice(); const bannerOnScreen = typeof this.optedInNoticeBannerId !== 'undefined'; - return !bannerOnScreen && userHasSeenOptedInNotice; + return !bannerOnScreen && userShouldSeeOptInNotice; }; public renderOptedInNoticeBanner = (): void => { diff --git a/src/plugins/telemetry/public/services/telemetry_service.test.ts b/src/plugins/telemetry/public/services/telemetry_service.test.ts index 16faa0cfc753..655bbfe746c2 100644 --- a/src/plugins/telemetry/public/services/telemetry_service.test.ts +++ b/src/plugins/telemetry/public/services/telemetry_service.test.ts @@ -184,15 +184,15 @@ describe('TelemetryService', () => { describe('setUserHasSeenNotice', () => { it('should hit the API and change the config', async () => { const telemetryService = mockTelemetryService({ - config: { telemetryNotifyUserAboutOptInDefault: undefined }, + config: { telemetryNotifyUserAboutOptInDefault: undefined, userCanChangeSettings: true }, }); expect(telemetryService.userHasSeenOptedInNotice).toBe(undefined); - expect(telemetryService.getUserHasSeenOptedInNotice()).toBe(false); + expect(telemetryService.getUserShouldSeeOptInNotice()).toBe(false); await telemetryService.setUserHasSeenNotice(); expect(telemetryService['http'].put).toBeCalledTimes(1); expect(telemetryService.userHasSeenOptedInNotice).toBe(true); - expect(telemetryService.getUserHasSeenOptedInNotice()).toBe(true); + expect(telemetryService.getUserShouldSeeOptInNotice()).toBe(true); }); it('should show a toast notification if the request fail', async () => { @@ -207,12 +207,33 @@ describe('TelemetryService', () => { }); expect(telemetryService.userHasSeenOptedInNotice).toBe(undefined); - expect(telemetryService.getUserHasSeenOptedInNotice()).toBe(false); + expect(telemetryService.getUserShouldSeeOptInNotice()).toBe(false); await telemetryService.setUserHasSeenNotice(); expect(telemetryService['http'].put).toBeCalledTimes(1); expect(telemetryService['notifications'].toasts.addError).toBeCalledTimes(1); expect(telemetryService.userHasSeenOptedInNotice).toBe(false); - expect(telemetryService.getUserHasSeenOptedInNotice()).toBe(false); + expect(telemetryService.getUserShouldSeeOptInNotice()).toBe(false); + }); + }); + + describe('getUserShouldSeeOptInNotice', () => { + it('returns whether the user can update the telemetry config (has SavedObjects access)', () => { + const telemetryService = mockTelemetryService({ + config: { userCanChangeSettings: undefined }, + }); + expect(telemetryService.config.userCanChangeSettings).toBe(undefined); + expect(telemetryService.userCanChangeSettings).toBe(false); + expect(telemetryService.getUserShouldSeeOptInNotice()).toBe(false); + + telemetryService.userCanChangeSettings = false; + expect(telemetryService.config.userCanChangeSettings).toBe(false); + expect(telemetryService.userCanChangeSettings).toBe(false); + expect(telemetryService.getUserShouldSeeOptInNotice()).toBe(false); + + telemetryService.userCanChangeSettings = true; + expect(telemetryService.config.userCanChangeSettings).toBe(true); + expect(telemetryService.userCanChangeSettings).toBe(true); + expect(telemetryService.getUserShouldSeeOptInNotice()).toBe(true); }); }); }); diff --git a/src/plugins/telemetry/public/services/telemetry_service.ts b/src/plugins/telemetry/public/services/telemetry_service.ts index 6d87a74197fe..c807aa9e1d35 100644 --- a/src/plugins/telemetry/public/services/telemetry_service.ts +++ b/src/plugins/telemetry/public/services/telemetry_service.ts @@ -87,9 +87,25 @@ export class TelemetryService { return telemetryUrl; }; - public getUserHasSeenOptedInNotice = () => { - return this.config.telemetryNotifyUserAboutOptInDefault || false; - }; + /** + * Returns if an user should be shown the notice about Opt-In/Out telemetry. + * The decision is made based on whether any user has already dismissed the message or + * the user can't actually change the settings (in which case, there's no point on bothering them) + */ + public getUserShouldSeeOptInNotice(): boolean { + return ( + (this.config.telemetryNotifyUserAboutOptInDefault && this.config.userCanChangeSettings) ?? + false + ); + } + + public get userCanChangeSettings() { + return this.config.userCanChangeSettings ?? false; + } + + public set userCanChangeSettings(userCanChangeSettings: boolean) { + this.config = { ...this.config, userCanChangeSettings }; + } public getIsOptedIn = () => { return this.isOptedIn; diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index acd575badbe5..5bce03a29276 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -414,6 +414,34 @@ } } }, + "enterpriseSearch": { + "properties": { + "clicks_total": { + "type": "long" + }, + "clicks_7_days": { + "type": "long" + }, + "clicks_30_days": { + "type": "long" + }, + "clicks_90_days": { + "type": "long" + }, + "minutes_on_screen_total": { + "type": "float" + }, + "minutes_on_screen_7_days": { + "type": "float" + }, + "minutes_on_screen_30_days": { + "type": "float" + }, + "minutes_on_screen_90_days": { + "type": "float" + } + } + }, "appSearch": { "properties": { "clicks_total": { diff --git a/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap b/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap index dd4ee61fd114..ab29656c557c 100644 --- a/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap +++ b/src/plugins/telemetry_management_section/public/components/__snapshots__/telemetry_management_section.test.tsx.snap @@ -228,7 +228,6 @@ exports[`TelemetryManagementSectionComponent renders null because allowChangingO "getIsOptedIn": [Function], "getOptInStatusUrl": [Function], "getTelemetryUrl": [Function], - "getUserHasSeenOptedInNotice": [Function], "http": Object { "addLoadingCountSource": [MockFunction], "anonymousPaths": Object { @@ -430,7 +429,6 @@ exports[`TelemetryManagementSectionComponent renders null because query does not "getIsOptedIn": [Function], "getOptInStatusUrl": [Function], "getTelemetryUrl": [Function], - "getUserHasSeenOptedInNotice": [Function], "http": Object { "addLoadingCountSource": [MockFunction], "anonymousPaths": Object { diff --git a/src/plugins/timelion/server/plugin.ts b/src/plugins/timelion/server/plugin.ts index fe77ebeb0866..d5a5ec4640d4 100644 --- a/src/plugins/timelion/server/plugin.ts +++ b/src/plugins/timelion/server/plugin.ts @@ -42,7 +42,7 @@ const showWarningMessageIfTimelionSheetWasFound = (core: CoreStart, logger: Logg ({ total }) => total && logger.warn( - 'Deprecated since 7.0, the Timelion app will be removed in 8.0. To continue using your Timelion worksheets, migrate them to a dashboard. See https://www.elastic.co/guide/en/kibana/master/timelion.html#timelion-deprecation.' + 'Deprecated since 7.0, the Timelion app will be removed in 8.0. To continue using your Timelion worksheets, migrate them to a dashboard. See https://www.elastic.co/guide/en/kibana/master/dashboard.html#timelion-deprecation.' ) ); }; diff --git a/src/plugins/ui_actions/public/tests/test_samples/hello_world_action.tsx b/src/plugins/ui_actions/public/tests/test_samples/hello_world_action.tsx index 8fff231a867b..a4cfe172dd10 100644 --- a/src/plugins/ui_actions/public/tests/test_samples/hello_world_action.tsx +++ b/src/plugins/ui_actions/public/tests/test_samples/hello_world_action.tsx @@ -18,7 +18,7 @@ */ import React from 'react'; -import { EuiFlyout, EuiFlexGroup, EuiFlexItem, EuiBadge } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiBadge, EuiFlyoutBody } from '@elastic/eui'; import { CoreStart } from 'src/core/public'; import { createAction, ActionByType } from '../../actions'; import { toMountPoint, reactToUiComponent } from '../../../../kibana_react/public'; @@ -49,14 +49,11 @@ export function createHelloWorldAction( getIconType: () => 'lock', MenuItem: UiMenuItem, execute: async () => { - const flyoutSession = overlays.openFlyout( - toMountPoint( - flyoutSession && flyoutSession.close()}> - Hello World, I am a hello world action! - - ), + overlays.openFlyout( + toMountPoint(Hello World, I am a hello world action!), { 'data-test-subj': 'helloWorldAction', + ownFocus: true, } ); }, diff --git a/src/plugins/vis_type_timelion/server/series_functions/es/es.test.js b/src/plugins/vis_type_timelion/server/series_functions/es/es.test.js index 4b5aab85cfc4..c5fc4b7b9326 100644 --- a/src/plugins/vis_type_timelion/server/series_functions/es/es.test.js +++ b/src/plugins/vis_type_timelion/server/series_functions/es/es.test.js @@ -100,9 +100,17 @@ describe('es', () => { expect(agg.time_buckets.date_histogram.time_zone).to.equal('Etc/UTC'); }); - it('sets the field and interval', () => { + it('sets the field', () => { expect(agg.time_buckets.date_histogram.field).to.equal('@timestamp'); - expect(agg.time_buckets.date_histogram.interval).to.equal('1y'); + }); + + it('sets the interval for calendar_interval correctly', () => { + expect(agg.time_buckets.date_histogram).to.have.property('calendar_interval', '1y'); + }); + + it('sets the interval for fixed_interval correctly', () => { + const a = createDateAgg({ timefield: '@timestamp', interval: '24h' }, tlConfig); + expect(a.time_buckets.date_histogram).to.have.property('fixed_interval', '24h'); }); it('sets min_doc_count to 0', () => { diff --git a/src/plugins/vis_type_timelion/server/series_functions/es/lib/create_date_agg.js b/src/plugins/vis_type_timelion/server/series_functions/es/lib/create_date_agg.js index 904fe69cbc57..b36f37ac5cc9 100644 --- a/src/plugins/vis_type_timelion/server/series_functions/es/lib/create_date_agg.js +++ b/src/plugins/vis_type_timelion/server/series_functions/es/lib/create_date_agg.js @@ -19,6 +19,8 @@ import _ from 'lodash'; import { buildAggBody } from './agg_body'; +import { search } from '../../../../../../plugins/data/server'; +const { dateHistogramInterval } = search.aggs; export default function createDateAgg(config, tlConfig, scriptedFields) { const dateAgg = { @@ -26,13 +28,13 @@ export default function createDateAgg(config, tlConfig, scriptedFields) { meta: { type: 'time_buckets' }, date_histogram: { field: config.timefield, - interval: config.interval, time_zone: tlConfig.time.timezone, extended_bounds: { min: tlConfig.time.from, max: tlConfig.time.to, }, min_doc_count: 0, + ...dateHistogramInterval(config.interval), }, }, }; diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_vars.js b/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_vars.js index f969778bbc61..34f339ce24c2 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_vars.js +++ b/src/plugins/vis_type_timeseries/public/application/components/lib/convert_series_to_vars.js @@ -54,6 +54,26 @@ export const convertSeriesToVars = (series, model, dateFormat = 'lll', getConfig }; set(variables, varName, data); set(variables, `${_.snakeCase(row.label)}.label`, row.label); + + /** + * Handle the case when a field has "key_as_string" value. + * Common case is the value is a date string (e.x. "2020-08-21T20:36:58.000Z") or a boolean stringified value ("true"/"false"). + * Try to convert the value into a moment object and format it with "dateFormat" from UI settings, + * if the "key_as_string" value is recognized by a known format in Moments.js https://momentjs.com/docs/#/parsing/string/ . + * If not, return a formatted value from elasticsearch + */ + if (row.labelFormatted) { + const momemntObj = moment(row.labelFormatted); + let val; + + if (momemntObj.isValid()) { + val = momemntObj.format(dateFormat); + } else { + val = row.labelFormatted; + } + + set(variables, `${_.snakeCase(row.label)}.formatted`, val); + } }); }); return variables; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.js index 54139a7c27e3..37cc7fd3380d 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.js @@ -42,6 +42,7 @@ export function getSplits(resp, panel, series, meta) { return buckets.map((bucket) => { bucket.id = `${series.id}:${bucket.key}`; bucket.label = formatKey(bucket.key, series); + bucket.labelFormatted = bucket.key_as_string || ''; bucket.color = panel.type === 'top_n' ? color.string() : colors.shift(); bucket.meta = meta; return bucket; diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js index 376d32d0da13..28f056613b08 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/helpers/get_splits.test.js @@ -89,6 +89,7 @@ describe('getSplits(resp, panel, series)', () => { id: 'SERIES:example-01', key: 'example-01', label: 'example-01', + labelFormatted: '', meta: { bucketSize: 10 }, color: 'rgb(255, 0, 0)', timeseries: { buckets: [] }, @@ -98,6 +99,7 @@ describe('getSplits(resp, panel, series)', () => { id: 'SERIES:example-02', key: 'example-02', label: 'example-02', + labelFormatted: '', meta: { bucketSize: 10 }, color: 'rgb(255, 0, 0)', timeseries: { buckets: [] }, @@ -145,6 +147,7 @@ describe('getSplits(resp, panel, series)', () => { id: 'SERIES:example-01', key: 'example-01', label: 'example-01', + labelFormatted: '', meta: { bucketSize: 10 }, color: undefined, timeseries: { buckets: [] }, @@ -154,6 +157,7 @@ describe('getSplits(resp, panel, series)', () => { id: 'SERIES:example-02', key: 'example-02', label: 'example-02', + labelFormatted: '', meta: { bucketSize: 10 }, color: undefined, timeseries: { buckets: [] }, diff --git a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.js b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.js index 0d567b7fd415..e04c3a93e81b 100644 --- a/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.js +++ b/src/plugins/vis_type_timeseries/server/lib/vis_data/response_processors/series/std_metric.js @@ -40,6 +40,7 @@ export function stdMetric(resp, panel, series, meta) { results.push({ id: `${split.id}`, label: split.label, + labelFormatted: split.labelFormatted, color: split.color, data, ...decoration, diff --git a/src/plugins/vis_type_vega/public/data_model/search_api.ts b/src/plugins/vis_type_vega/public/data_model/search_api.ts index 8a1541ecae0d..4ea25af54924 100644 --- a/src/plugins/vis_type_vega/public/data_model/search_api.ts +++ b/src/plugins/vis_type_vega/public/data_model/search_api.ts @@ -51,9 +51,6 @@ export class SearchAPI { searchRequests.map((request) => { const requestId = request.name; const params = getSearchParamsFromRequest(request, { - esShardTimeout: this.dependencies.injectedMetadata.getInjectedVar( - 'esShardTimeout' - ) as number, getConfig: this.dependencies.uiSettings.get.bind(this.dependencies.uiSettings), }); diff --git a/src/plugins/vis_type_vega/public/plugin.ts b/src/plugins/vis_type_vega/public/plugin.ts index 00c6b2e3c8d5..4b8ff8e2cb43 100644 --- a/src/plugins/vis_type_vega/public/plugin.ts +++ b/src/plugins/vis_type_vega/public/plugin.ts @@ -78,7 +78,6 @@ export class VegaPlugin implements Plugin, void> { ) { setInjectedVars({ enableExternalUrls: this.initializerContext.config.get().enableExternalUrls, - esShardTimeout: core.injectedMetadata.getInjectedVar('esShardTimeout') as number, emsTileLayerId: core.injectedMetadata.getInjectedVar('emsTileLayerId', true), }); setUISettings(core.uiSettings); diff --git a/src/plugins/vis_type_vega/public/services.ts b/src/plugins/vis_type_vega/public/services.ts index acd02a6dd42f..dfb2c96e9f89 100644 --- a/src/plugins/vis_type_vega/public/services.ts +++ b/src/plugins/vis_type_vega/public/services.ts @@ -48,7 +48,6 @@ export const [getSavedObjects, setSavedObjects] = createGetterSetter('InjectedVars'); diff --git a/src/plugins/vis_type_vega/public/vega_visualization.test.js b/src/plugins/vis_type_vega/public/vega_visualization.test.js index 0912edf9503a..1bf625af7620 100644 --- a/src/plugins/vis_type_vega/public/vega_visualization.test.js +++ b/src/plugins/vis_type_vega/public/vega_visualization.test.js @@ -82,7 +82,6 @@ describe('VegaVisualizations', () => { setInjectedVars({ emsTileLayerId: {}, enableExternalUrls: true, - esShardTimeout: 10000, }); setData(dataPluginStart); setSavedObjects(coreStart.savedObjects); diff --git a/tasks/config/run.js b/tasks/config/run.js index 132b51765b3e..148be6ea8afa 100644 --- a/tasks/config/run.js +++ b/tasks/config/run.js @@ -154,12 +154,6 @@ module.exports = function () { args: ['scripts/test_hardening.js'], }), - test_package_safer_lodash_set: scriptWithGithubChecks({ - title: '@elastic/safer-lodash-set tests', - cmd: YARN, - args: ['--cwd', 'packages/elastic-safer-lodash-set', 'test'], - }), - apiIntegrationTests: scriptWithGithubChecks({ title: 'API integration tests', cmd: NODE, diff --git a/tasks/jenkins.js b/tasks/jenkins.js index adfb6f0f4686..90efadf41c43 100644 --- a/tasks/jenkins.js +++ b/tasks/jenkins.js @@ -38,7 +38,6 @@ module.exports = function (grunt) { 'run:test_jest_integration', 'run:test_projects', 'run:test_hardening', - 'run:test_package_safer_lodash_set', 'run:apiIntegrationTests', ]); }; diff --git a/test/api_integration/apis/saved_objects/migrations.ts b/test/api_integration/apis/saved_objects/migrations.ts index 9997d9710e21..99a58620b17f 100644 --- a/test/api_integration/apis/saved_objects/migrations.ts +++ b/test/api_integration/apis/saved_objects/migrations.ts @@ -379,14 +379,12 @@ async function migrateIndex({ index, migrations, mappingProperties, - validateDoc, obsoleteIndexTemplatePattern, }: { esClient: ElasticsearchClient; index: string; migrations: Record; mappingProperties: SavedObjectsTypeMappingDefinitions; - validateDoc?: (doc: any) => void; obsoleteIndexTemplatePattern?: string; }) { const typeRegistry = new SavedObjectTypeRegistry(); @@ -396,7 +394,6 @@ async function migrateIndex({ const documentMigrator = new DocumentMigrator({ kibanaVersion: '99.9.9', typeRegistry, - validateDoc: validateDoc || _.noop, log: getLogMock(), }); diff --git a/test/api_integration/apis/stats/stats.js b/test/api_integration/apis/stats/stats.js index a40427fea8b9..0972f0ebebf0 100644 --- a/test/api_integration/apis/stats/stats.js +++ b/test/api_integration/apis/stats/stats.js @@ -55,7 +55,12 @@ const assertStatsAndMetrics = (body) => { export default function ({ getService }) { const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + describe('kibana stats api', () => { + before('make sure there are some saved objects', () => esArchiver.load('saved_objects/basic')); + after('cleanup saved objects changes', () => esArchiver.unload('saved_objects/basic')); + describe('basic', () => { it('should return the stats without cluster_uuid with no query string params', () => { return supertest diff --git a/test/api_integration/apis/telemetry/telemetry_local.js b/test/api_integration/apis/telemetry/telemetry_local.js index 8b10f412fae2..d2d61705b763 100644 --- a/test/api_integration/apis/telemetry/telemetry_local.js +++ b/test/api_integration/apis/telemetry/telemetry_local.js @@ -38,8 +38,12 @@ function flatKeys(source) { export default function ({ getService }) { const supertest = getService('supertest'); const es = getService('es'); + const esArchiver = getService('esArchiver'); describe('/api/telemetry/v2/clusters/_stats', () => { + before('make sure there are some saved objects', () => esArchiver.load('saved_objects/basic')); + after('cleanup saved objects changes', () => esArchiver.unload('saved_objects/basic')); + before('create some telemetry-data tracked indices', async () => { return es.indices.create({ index: 'filebeat-telemetry_tests_logs' }); }); diff --git a/test/functional/apps/management/_create_index_pattern_wizard.js b/test/functional/apps/management/_create_index_pattern_wizard.js index 976052737140..8b11a02099f6 100644 --- a/test/functional/apps/management/_create_index_pattern_wizard.js +++ b/test/functional/apps/management/_create_index_pattern_wizard.js @@ -66,6 +66,18 @@ export default function ({ getService, getPageObjects }) { await PageObjects.settings.createIndexPattern('alias1', false); }); + + after(async () => { + await es.transport.request({ + path: '/_aliases', + method: 'POST', + body: { actions: [{ remove: { index: 'blogs', alias: 'alias1' } }] }, + }); + await es.transport.request({ + path: '/blogs', + method: 'DELETE', + }); + }); }); }); } diff --git a/test/plugin_functional/plugins/index_patterns/server/plugin.ts b/test/plugin_functional/plugins/index_patterns/server/plugin.ts index d6a4fdd67b0a..1c85f226623c 100644 --- a/test/plugin_functional/plugins/index_patterns/server/plugin.ts +++ b/test/plugin_functional/plugins/index_patterns/server/plugin.ts @@ -78,7 +78,7 @@ export class IndexPatternsTestPlugin const id = (req.params as Record).id; const service = await data.indexPatterns.indexPatternsServiceFactory(req); const ip = await service.get(id); - await ip.save(); + await service.save(ip); return res.ok(); } ); diff --git a/test/scripts/test/safer_lodash_set.sh b/test/scripts/test/safer_lodash_set.sh deleted file mode 100755 index 4d7f9c28210d..000000000000 --- a/test/scripts/test/safer_lodash_set.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -source src/dev/ci_setup/setup_env.sh - -yarn run grunt run:test_package_safer_lodash_set diff --git a/vars/tasks.groovy b/vars/tasks.groovy index 52641ce31f0b..edd2c0aa4740 100644 --- a/vars/tasks.groovy +++ b/vars/tasks.groovy @@ -34,7 +34,6 @@ def test() { kibanaPipeline.scriptTask('Jest Unit Tests', 'test/scripts/test/jest_unit.sh'), kibanaPipeline.scriptTask('API Integration Tests', 'test/scripts/test/api_integration.sh'), - kibanaPipeline.scriptTask('@elastic/safer-lodash-set Tests', 'test/scripts/test/safer_lodash_set.sh'), kibanaPipeline.scriptTask('X-Pack SIEM cyclic dependency', 'test/scripts/test/xpack_siem_cyclic_dependency.sh'), kibanaPipeline.scriptTask('X-Pack List cyclic dependency', 'test/scripts/test/xpack_list_cyclic_dependency.sh'), kibanaPipeline.scriptTask('X-Pack Jest Unit Tests', 'test/scripts/test/xpack_jest_unit.sh'), diff --git a/x-pack/package.json b/x-pack/package.json index 899eca109592..3a074ba1f1d7 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -195,7 +195,7 @@ "jsdom": "13.1.0", "jsondiffpatch": "0.4.1", "jsts": "^1.6.2", - "kea": "2.2.0-rc.4", + "kea": "^2.2.0", "loader-utils": "^1.2.3", "lz-string": "^1.4.4", "madge": "3.4.4", diff --git a/x-pack/plugins/actions/README.md b/x-pack/plugins/actions/README.md index 868f6f180cc9..3bc8acead6c1 100644 --- a/x-pack/plugins/actions/README.md +++ b/x-pack/plugins/actions/README.md @@ -19,7 +19,7 @@ Table of Contents - [Usage](#usage) - [Kibana Actions Configuration](#kibana-actions-configuration) - [Configuration Options](#configuration-options) - - [Adding Built-in Action Types to allowedHosts](#adding-built-in-action-types-to-hosts-allow-list) + - [Adding Built-in Action Types to allowedHosts](#adding-built-in-action-types-to-allowedhosts) - [Configuration Utilities](#configuration-utilities) - [Action types](#action-types) - [Methods](#methods) @@ -74,13 +74,21 @@ Table of Contents - [`secrets`](#secrets-7) - [`params`](#params-7) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-1) + - [`subActionParams (issueTypes)`](#subactionparams-issuetypes) + - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-2) - [IBM Resilient](#ibm-resilient) - [`config`](#config-8) - [`secrets`](#secrets-8) - [`params`](#params-8) - - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-2) + - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-3) - [Command Line Utility](#command-line-utility) - [Developing New Action Types](#developing-new-action-types) + - [licensing](#licensing) + - [plugin location](#plugin-location) + - [documentation](#documentation) + - [tests](#tests) + - [action type config and secrets](#action-type-config-and-secrets) + - [user interface](#user-interface) ## Terminology @@ -103,12 +111,12 @@ Implemented under the [Actions Config](./server/actions_config.ts). Built-In-Actions are configured using the _xpack.actions_ namespoace under _kibana.yml_, and have the following configuration options: -| Namespaced Key | Description | Type | -| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | -| _xpack.actions._**enabled** | Feature toggle which enabled Actions in Kibana. | boolean | -| _xpack.actions._**allowedHosts** | Which _hostnames_ are allowed for the Built-In-Action? This list should contain hostnames of every external service you wish to interact with using Webhooks, Email or any other built in Action. Note that you may use the string "\*" in place of a specific hostname to enable Kibana to target any URL, but keep in mind the potential use of such a feature to execute [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) attacks from your server. | Array | -| _xpack.actions._**enabledActionTypes** | A list of _actionTypes_ id's that are enabled. A "\*" may be used as an element to indicate all registered actionTypes should be enabled. The actionTypes registered for Kibana are `.server-log`, `.slack`, `.email`, `.index`, `.pagerduty`, `.webhook`. Default: `["*"]` | Array | -| _xpack.actions._**preconfigured** | A object of action id / preconfigured actions. Default: `{}` | Array | +| Namespaced Key | Description | Type | +| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | +| _xpack.actions._**enabled** | Feature toggle which enabled Actions in Kibana. | boolean | +| _xpack.actions._**allowedHosts** | Which _hostnames_ are allowed for the Built-In-Action? This list should contain hostnames of every external service you wish to interact with using Webhooks, Email or any other built in Action. Note that you may use the string "\*" in place of a specific hostname to enable Kibana to target any URL, but keep in mind the potential use of such a feature to execute [SSRF](https://www.owasp.org/index.php/Server_Side_Request_Forgery) attacks from your server. | Array | +| _xpack.actions._**enabledActionTypes** | A list of _actionTypes_ id's that are enabled. A "\*" may be used as an element to indicate all registered actionTypes should be enabled. The actionTypes registered for Kibana are `.server-log`, `.slack`, `.email`, `.index`, `.pagerduty`, `.webhook`. Default: `["*"]` | Array | +| _xpack.actions._**preconfigured** | A object of action id / preconfigured actions. Default: `{}` | Array | #### Adding Built-in Action Types to allowedHosts @@ -120,14 +128,14 @@ Uniquely, the _PagerDuty Action Type_ has been configured to support the service This module provides a Utilities for interacting with the configuration. -| Method | Arguments | Description | Return Type | -| ------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | -| isUriAllowed | _uri_: The URI you wish to validate is allowed | Validates whether the URI is allowed. This checks the configuration and validates that the hostname of the URI is in the list of allowed Hosts and returns `true` if it is allowed. If the configuration says that all URI's are allowed (using an "\*") then it will always return `true`. | Boolean | -| isHostnameAllowed | _hostname_: The Hostname you wish to validate is allowed | Validates whether the Hostname is allowed. This checks the configuration and validates that the hostname is in the list of allowed Hosts and returns `true` if it is allowed. If the configuration says that all Hostnames are allowed (using an "\*") then it will always return `true`. | Boolean | -| isActionTypeEnabled | _actionType_: The actionType to check to see if it's enabled | Returns true if the actionType is enabled, otherwise false. | Boolean | -| ensureUriAllowed | _uri_: The URI you wish to validate is allowed | Validates whether the URI is allowed. This checks the configuration and validates that the hostname of the URI is in the list of allowed Hosts and throws an error if it is not allowed. If the configuration says that all URI's are allowed (using an "\*") then it will never throw. | No return value, throws if URI isn't allowed | -| ensureHostnameAllowed | _hostname_: The Hostname you wish to validate is allowed | Validates whether the Hostname is allowed. This checks the configuration and validates that the hostname is in the list of allowed Hosts and throws an error if it is not allowed. If the configuration says that all Hostnames are allowed (using an "\*") then it will never throw | No return value, throws if Hostname isn't allowed . | -| ensureActionTypeEnabled | _actionType_: The actionType to check to see if it's enabled | Throws an error if the actionType is not enabled | No return value, throws if actionType isn't enabled | +| Method | Arguments | Description | Return Type | +| ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | +| isUriAllowed | _uri_: The URI you wish to validate is allowed | Validates whether the URI is allowed. This checks the configuration and validates that the hostname of the URI is in the list of allowed Hosts and returns `true` if it is allowed. If the configuration says that all URI's are allowed (using an "\*") then it will always return `true`. | Boolean | +| isHostnameAllowed | _hostname_: The Hostname you wish to validate is allowed | Validates whether the Hostname is allowed. This checks the configuration and validates that the hostname is in the list of allowed Hosts and returns `true` if it is allowed. If the configuration says that all Hostnames are allowed (using an "\*") then it will always return `true`. | Boolean | +| isActionTypeEnabled | _actionType_: The actionType to check to see if it's enabled | Returns true if the actionType is enabled, otherwise false. | Boolean | +| ensureUriAllowed | _uri_: The URI you wish to validate is allowed | Validates whether the URI is allowed. This checks the configuration and validates that the hostname of the URI is in the list of allowed Hosts and throws an error if it is not allowed. If the configuration says that all URI's are allowed (using an "\*") then it will never throw. | No return value, throws if URI isn't allowed | +| ensureHostnameAllowed | _hostname_: The Hostname you wish to validate is allowed | Validates whether the Hostname is allowed. This checks the configuration and validates that the hostname is in the list of allowed Hosts and throws an error if it is not allowed. If the configuration says that all Hostnames are allowed (using an "\*") then it will never throw | No return value, throws if Hostname isn't allowed . | +| ensureActionTypeEnabled | _actionType_: The actionType to check to see if it's enabled | Throws an error if the actionType is not enabled | No return value, throws if actionType isn't enabled | ## Action types @@ -442,7 +450,7 @@ The config and params properties are modelled after the [Watcher Index Action](h | index | The Elasticsearch index to index into. | string _(optional)_ | | doc_id | The optional \_id of the document. | string _(optional)_ | | execution_time_field | The field that will store/index the action execution time. | string _(optional)_ | -| refresh | Setting of the refresh policy for the write request. | boolean _(optional)_ | +| refresh | Setting of the refresh policy for the write request. | boolean _(optional)_ | ### `secrets` @@ -450,9 +458,9 @@ This action type has no `secrets` properties. ### `params` -| Property | Description | Type | -| --------- | ---------------------------------------- | ------------------- | -| documents | JSON object that describes the [document](https://www.elastic.co/guide/en/elasticsearch/reference/current/getting-started-index.html#getting-started-batch-processing). | object[] | +| Property | Description | Type | +| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | +| documents | JSON object that describes the [document](https://www.elastic.co/guide/en/elasticsearch/reference/current/getting-started-index.html#getting-started-batch-processing). | object[] | --- @@ -529,10 +537,10 @@ The ServiceNow action uses the [V2 Table API](https://developer.servicenow.com/a ### `config` -| Property | Description | Type | -| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -| apiUrl | ServiceNow instance URL. | string | -| casesConfiguration | Case configuration object. The object should contain an attribute called `mapping`. A `mapping` is an array of objects. Each mapping object should be of the form `{ source: string, target: string, actionType: string }`. `source` is the Case field. `target` is the ServiceNow field where `source` will be mapped to. `actionType` can be one of `nothing`, `overwrite` or `append`. For example the `{ source: 'title', target: 'short_description', actionType: 'overwrite' }` record, inside mapping array, means that the title of a case will be mapped to the short description of an incident in ServiceNow and will be overwrite on each update. | object | +| Property | Description | Type | +| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------- | +| apiUrl | ServiceNow instance URL. | string | +| incidentConfiguration | Optional property and specific to **Cases only**. If defined, the object should contain an attribute called `mapping`. A `mapping` is an array of objects. Each mapping object should be of the form `{ source: string, target: string, actionType: string }`. `source` is the Case field. `target` is the ServiceNow field where `source` will be mapped to. `actionType` can be one of `nothing`, `overwrite` or `append`. For example the `{ source: 'title', target: 'short_description', actionType: 'overwrite' }` record, inside mapping array, means that the title of a case will be mapped to the short description of an incident in ServiceNow and will be overwrite on each update. | object _(optional)_ | ### `secrets` @@ -550,13 +558,17 @@ The ServiceNow action uses the [V2 Table API](https://developer.servicenow.com/a #### `subActionParams (pushToService)` -| Property | Description | Type | -| ----------- | -------------------------------------------------------------------------------------------------------------------------- | --------------------- | -| caseId | The case id | string | -| title | The title of the case | string _(optional)_ | -| description | The description of the case | string _(optional)_ | -| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }` | object[] _(optional)_ | -| externalId | The id of the incident in ServiceNow . If presented the incident will be update. Otherwise a new incident will be created. | string _(optional)_ | +| Property | Description | Type | +| ------------- | ------------------------------------------------------------------------------------------------------------------------- | --------------------- | +| savedObjectId | The id of the saved object. | string | +| title | The title of the case. | string _(optional)_ | +| description | The description of the case. | string _(optional)_ | +| comment | A comment. | string _(optional)_ | +| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }`. | object[] _(optional)_ | +| externalId | The id of the incident in ServiceNow. If presented the incident will be update. Otherwise a new incident will be created. | string _(optional)_ | +| severity | The name of the severity in ServiceNow. | string _(optional)_ | +| urgency | The name of the urgency in ServiceNow. | string _(optional)_ | +| impact | The name of the impact in ServiceNow. | string _(optional)_ | --- @@ -568,34 +580,47 @@ The Jira action uses the [V2 API](https://developer.atlassian.com/cloud/jira/pla ### `config` -| Property | Description | Type | -| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -| apiUrl | Jira instance URL. | string | -| casesConfiguration | Case configuration object. The object should contain an attribute called `mapping`. A `mapping` is an array of objects. Each mapping object should be of the form `{ source: string, target: string, actionType: string }`. `source` is the Case field. `target` is the Jira field where `source` will be mapped to. `actionType` can be one of `nothing`, `overwrite` or `append`. For example the `{ source: 'title', target: 'summary', actionType: 'overwrite' }` record, inside mapping array, means that the title of a case will be mapped to the short description of an incident in Jira and will be overwrite on each update. | object | +| Property | Description | Type | +| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | +| apiUrl | Jira instance URL. | string | +| incidentConfiguration | Optional property and specific to **Cases only**. if defined, the object should contain an attribute called `mapping`. A `mapping` is an array of objects. Each mapping object should be of the form `{ source: string, target: string, actionType: string }`. `source` is the Case field. `target` is the Jira field where `source` will be mapped to. `actionType` can be one of `nothing`, `overwrite` or `append`. For example the `{ source: 'title', target: 'summary', actionType: 'overwrite' }` record, inside mapping array, means that the title of a case will be mapped to the short description of an incident in Jira and will be overwrite on each update. | object _(optional)_ | ### `secrets` -| Property | Description | Type | -| -------- | --------------------------------------- | ------ | -| email | email for HTTP Basic authentication | string | -| apiToken | API token for HTTP Basic authentication | string | +| Property | Description | Type | +| -------- | ----------------------------------------------------- | ------ | +| email | email (or username) for HTTP Basic authentication | string | +| apiToken | API token (or password) for HTTP Basic authentication | string | ### `params` -| Property | Description | Type | -| --------------- | ------------------------------------------------------------------------------------ | ------ | -| subAction | The sub action to perform. It can be `pushToService`, `handshake`, and `getIncident` | string | -| subActionParams | The parameters of the sub action | object | +| Property | Description | Type | +| --------------- | ----------------------------------------------------------------------------------------------------------------------- | ------ | +| subAction | The sub action to perform. It can be `pushToService`, `handshake`, `getIncident`, `issueTypes`, and `fieldsByIssueType` | string | +| subActionParams | The parameters of the sub action | object | + +#### `subActionParams (pushToService)` + +| Property | Description | Type | +| ------------- | ------------------------------------------------------------------------------------------------------------------- | --------------------- | +| savedObjectId | The id of the saved object | string | +| title | The title of the case | string _(optional)_ | +| description | The description of the case | string _(optional)_ | +| externalId | The id of the incident in Jira. If presented the incident will be update. Otherwise a new incident will be created. | string _(optional)_ | +| issueType | The id of the issue type in Jira. | string _(optional)_ | +| priority | The name of the priority in Jira. Example: `Medium`. | string _(optional)_ | +| labels | An array of labels. | string[] _(optional)_ | +| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }` | object[] _(optional)_ | + +#### `subActionParams (issueTypes)` + +No parameters for `issueTypes` sub-action. Provide an empty object `{}`. #### `subActionParams (pushToService)` -| Property | Description | Type | -| ----------- | ------------------------------------------------------------------------------------------------------------------- | --------------------- | -| caseId | The case id | string | -| title | The title of the case | string _(optional)_ | -| description | The description of the case | string _(optional)_ | -| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }` | object[] _(optional)_ | -| externalId | The id of the incident in Jira. If presented the incident will be update. Otherwise a new incident will be created. | string _(optional)_ | +| Property | Description | Type | +| -------- | -------------------------------- | ------ | +| id | The id of the issue type in Jira | string | ## IBM Resilient @@ -603,10 +628,10 @@ ID: `.resilient` ### `config` -| Property | Description | Type | -| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------ | -| apiUrl | IBM Resilient instance URL. | string | -| casesConfiguration | Case configuration object. The object should contain an attribute called `mapping`. A `mapping` is an array of objects. Each mapping object should be of the form `{ source: string, target: string, actionType: string }`. `source` is the Case field. `target` is the Jira field where `source` will be mapped to. `actionType` can be one of `nothing`, `overwrite` or `append`. For example the `{ source: 'title', target: 'summary', actionType: 'overwrite' }` record, inside mapping array, means that the title of a case will be mapped to the short description of an incident in IBM Resilient and will be overwrite on each update. | object | +| Property | Description | Type | +| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------ | +| apiUrl | IBM Resilient instance URL. | string | +| incidentConfiguration | Case configuration object. The object should contain an attribute called `mapping`. A `mapping` is an array of objects. Each mapping object should be of the form `{ source: string, target: string, actionType: string }`. `source` is the Case field. `target` is the Jira field where `source` will be mapped to. `actionType` can be one of `nothing`, `overwrite` or `append`. For example the `{ source: 'title', target: 'summary', actionType: 'overwrite' }` record, inside mapping array, means that the title of a case will be mapped to the short description of an incident in IBM Resilient and will be overwrite on each update. | object | ### `secrets` @@ -624,13 +649,13 @@ ID: `.resilient` #### `subActionParams (pushToService)` -| Property | Description | Type | -| ----------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------- | -| caseId | The case id | string | -| title | The title of the case | string _(optional)_ | -| description | The description of the case | string _(optional)_ | -| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }` | object[] _(optional)_ | -| externalId | The id of the incident in IBM Resilient. If presented the incident will be update. Otherwise a new incident will be created. | string _(optional)_ | +| Property | Description | Type | +| ------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------- | +| savedObjectId | The id of the saved object | string | +| title | The title of the case | string _(optional)_ | +| description | The description of the case | string _(optional)_ | +| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }` | object[] _(optional)_ | +| externalId | The id of the incident in IBM Resilient. If presented the incident will be update. Otherwise a new incident will be created. | string _(optional)_ | # Command Line Utility @@ -660,30 +685,30 @@ Consider working with the alerting team on early structure /design feedback of n ## licensing -Currently actions are licensed as "basic" if the action only interacts with the stack, eg the server log and es index actions. Other actions are at least "gold" level. +Currently actions are licensed as "basic" if the action only interacts with the stack, eg the server log and es index actions. Other actions are at least "gold" level. ## plugin location -Currently actions that are licensed as "basic" **MUST** be implemented in the actions plugin, other actions can be implemented in any other plugin that pre-reqs the actions plugin. If the new action is generic across the stack, it probably belongs in the actions plugin, but if your action is very specific to a plugin/solution, it might be easiest to implement it in the plugin/solution. Keep in mind that if Kibana is run without the plugin being enabled, any actions defined in that plugin will not run, nor will those actions be available via APIs or UI. +Currently actions that are licensed as "basic" **MUST** be implemented in the actions plugin, other actions can be implemented in any other plugin that pre-reqs the actions plugin. If the new action is generic across the stack, it probably belongs in the actions plugin, but if your action is very specific to a plugin/solution, it might be easiest to implement it in the plugin/solution. Keep in mind that if Kibana is run without the plugin being enabled, any actions defined in that plugin will not run, nor will those actions be available via APIs or UI. -Actions that take URLs or hostnames should check that those values are allowed. The allowed host list utilities are currently internal to the actions plugin, and so such actions will need to be implemented in the actions plugin. Longer-term, we will expose these utilities so they can be used by alerts implemented in other plugins; see [issue #64659](https://github.com/elastic/kibana/issues/64659). +Actions that take URLs or hostnames should check that those values are allowed. The allowed host list utilities are currently internal to the actions plugin, and so such actions will need to be implemented in the actions plugin. Longer-term, we will expose these utilities so they can be used by alerts implemented in other plugins; see [issue #64659](https://github.com/elastic/kibana/issues/64659). ## documentation -You should also create some asciidoc for the new action type. An entry should be made in the action type index - [`docs/user/alerting/action-types.asciidoc`](../../../docs/user/alerting/action-types.asciidoc) which points to a new document for the action type that should be in the directory [`docs/user/alerting/action-types`](../../../docs/user/alerting/action-types). +You should also create some asciidoc for the new action type. An entry should be made in the action type index - [`docs/user/alerting/action-types.asciidoc`](../../../docs/user/alerting/action-types.asciidoc) which points to a new document for the action type that should be in the directory [`docs/user/alerting/action-types`](../../../docs/user/alerting/action-types). ## tests -The action type should have both jest tests and functional tests. For functional tests, if your action interacts with a 3rd party service via HTTP, you may be able to create a simulator for your service, to test with. See the existing functional test servers in the directory [`x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server`](../../test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server) +The action type should have both jest tests and functional tests. For functional tests, if your action interacts with a 3rd party service via HTTP, you may be able to create a simulator for your service, to test with. See the existing functional test servers in the directory [`x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server`](../../test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server) ## action type config and secrets -Action types must define `config` and `secrets` which are used to create connectors. This data should be described with `@kbn/config-schema` object schemas, and you **MUST NOT** use `schema.maybe()` to define properties. +Action types must define `config` and `secrets` which are used to create connectors. This data should be described with `@kbn/config-schema` object schemas, and you **MUST NOT** use `schema.maybe()` to define properties. -This is due to the fact that the structures are persisted in saved objects, which performs partial updates on the persisted data. If a property value is already persisted, but an update either doesn't include the property, or sets it to `undefined`, the persisted value will not be changed. Beyond this being a semantic error in general, it also ends up invalidating the encryption used to save secrets, and will render the secrets will not be able to be unencrypted later. +This is due to the fact that the structures are persisted in saved objects, which performs partial updates on the persisted data. If a property value is already persisted, but an update either doesn't include the property, or sets it to `undefined`, the persisted value will not be changed. Beyond this being a semantic error in general, it also ends up invalidating the encryption used to save secrets, and will render the secrets will not be able to be unencrypted later. -Instead of `schema.maybe()`, use `schema.nullable()`, which is the same as `schema.maybe()` except that when passed an `undefined` value, the object returned from the validation will be set to `null`. The resulting type will be `property-type | null`, whereas with `schema.maybe()` it would be `property-type | undefined`. +Instead of `schema.maybe()`, use `schema.nullable()`, which is the same as `schema.maybe()` except that when passed an `undefined` value, the object returned from the validation will be set to `null`. The resulting type will be `property-type | null`, whereas with `schema.maybe()` it would be `property-type | undefined`. ## user interface -In order to make this action usable in the Kibana UI, you will need to provide all the UI editing aspects of the action. The existing action type user interfaces are defined in [`x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types`](../triggers_actions_ui/public/application/components/builtin_action_types). For more information, see the [UI documentation](../triggers_actions_ui/README.md#create-and-register-new-action-type-ui). +In order to make this action usable in the Kibana UI, you will need to provide all the UI editing aspects of the action. The existing action type user interfaces are defined in [`x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types`](../triggers_actions_ui/public/application/components/builtin_action_types). For more information, see the [UI documentation](../triggers_actions_ui/README.md#create-and-register-new-action-type-ui). diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/case_shema.ts b/x-pack/plugins/actions/server/builtin_action_types/case/common_schema.ts similarity index 72% rename from x-pack/plugins/actions/server/builtin_action_types/servicenow/case_shema.ts rename to x-pack/plugins/actions/server/builtin_action_types/case/common_schema.ts index 2df8c8156cde..5a23eb89339e 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/case_shema.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/case/common_schema.ts @@ -22,13 +22,20 @@ export const IncidentConfigurationSchema = schema.object({ mapping: schema.arrayOf(MapRecordSchema), }); +export const UserSchema = schema.object({ + fullName: schema.nullable(schema.string()), + username: schema.nullable(schema.string()), +}); + export const EntityInformation = { - createdAt: schema.maybe(schema.string()), - createdBy: schema.maybe(schema.any()), + createdAt: schema.nullable(schema.string()), + createdBy: schema.nullable(UserSchema), updatedAt: schema.nullable(schema.string()), - updatedBy: schema.nullable(schema.any()), + updatedBy: schema.nullable(UserSchema), }; +export const EntityInformationSchema = schema.object(EntityInformation); + export const CommentSchema = schema.object({ commentId: schema.string(), comment: schema.string(), diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/case_types.ts b/x-pack/plugins/actions/server/builtin_action_types/case/common_types.ts similarity index 53% rename from x-pack/plugins/actions/server/builtin_action_types/servicenow/case_types.ts rename to x-pack/plugins/actions/server/builtin_action_types/case/common_types.ts index 49b85f9254af..cca83fb88ca9 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/case_types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/case/common_types.ts @@ -6,15 +6,11 @@ import { TypeOf } from '@kbn/config-schema'; import { - ExecutorSubActionGetIncidentParamsSchema, - ExecutorSubActionHandshakeParamsSchema, -} from './schema'; -import { IncidentConfigurationSchema, MapRecordSchema } from './case_shema'; -import { - PushToServiceApiParams, - ExternalServiceIncidentResponse, - ExternalServiceParams, -} from './types'; + IncidentConfigurationSchema, + MapRecordSchema, + CommentSchema, + EntityInformationSchema, +} from './common_schema'; export interface CreateCommentRequest { [key: string]: string; @@ -22,6 +18,8 @@ export interface CreateCommentRequest { export type IncidentConfiguration = TypeOf; export type MapRecord = TypeOf; +export type Comment = TypeOf; +export type EntityInformation = TypeOf; export interface ExternalServiceCommentResponse { commentId: string; @@ -29,18 +27,6 @@ export interface ExternalServiceCommentResponse { externalCommentId?: string; } -export type ExecutorSubActionGetIncidentParams = TypeOf< - typeof ExecutorSubActionGetIncidentParamsSchema ->; - -export type ExecutorSubActionHandshakeParams = TypeOf< - typeof ExecutorSubActionHandshakeParamsSchema ->; - -export interface PushToServiceResponse extends ExternalServiceIncidentResponse { - comments?: ExternalServiceCommentResponse[]; -} - export interface PipedField { key: string; value: string; @@ -48,10 +34,10 @@ export interface PipedField { pipes: string[]; } -export interface TransformFieldsArgs { - params: PushToServiceApiParams; +export interface TransformFieldsArgs { + params: P; fields: PipedField[]; - currentIncident?: ExternalServiceParams; + currentIncident?: S; } export interface TransformerArgs { diff --git a/x-pack/plugins/actions/server/builtin_action_types/case/utils.ts b/x-pack/plugins/actions/server/builtin_action_types/case/utils.ts index d895bf386a36..701bbea14fde 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/case/utils.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/case/utils.ts @@ -51,10 +51,7 @@ export const buildMap = (mapping: MapRecord[]): Map => { }, new Map()); }; -export const mapParams = ( - params: Partial, - mapping: Map -): AnyParams => { +export const mapParams = (params: T, mapping: Map): AnyParams => { return Object.keys(params).reduce((prev: AnyParams, curr: string): AnyParams => { const field = mapping.get(curr); if (field) { @@ -106,7 +103,10 @@ export const createConnectorExecutor = ({ const { comments, externalId, ...restParams } = pushToServiceParams; const mapping = buildMap(config.casesConfiguration.mapping); - const externalCase = mapParams(restParams, mapping); + const externalCase = mapParams( + restParams as ExecutorSubActionPushParams, + mapping + ); data = await api.pushToService({ externalService, diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts index bcfb82077d28..4495c37f758e 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts @@ -4,15 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import { api } from '../case/api'; +import { Logger } from '../../../../../../src/core/server'; import { externalServiceMock, mapping, apiParams } from './mocks'; -import { ExternalService } from '../case/types'; +import { ExternalService } from './types'; +import { api } from './api'; +let mockedLogger: jest.Mocked; describe('api', () => { let externalService: jest.Mocked; beforeEach(() => { externalService = externalServiceMock.create(); + jest.clearAllMocks(); }); afterEach(() => { @@ -20,10 +23,15 @@ describe('api', () => { }); describe('pushToService', () => { - describe('create incident', () => { + describe('create incident - cases', () => { test('it creates an incident', async () => { const params = { ...apiParams, externalId: null }; - const res = await api.pushToService({ externalService, mapping, params }); + const res = await api.pushToService({ + externalService, + mapping, + params, + logger: mockedLogger, + }); expect(res).toEqual({ id: 'incident-1', @@ -45,7 +53,12 @@ describe('api', () => { test('it creates an incident without comments', async () => { const params = { ...apiParams, externalId: null, comments: [] }; - const res = await api.pushToService({ externalService, mapping, params }); + const res = await api.pushToService({ + externalService, + mapping, + params, + logger: mockedLogger, + }); expect(res).toEqual({ id: 'incident-1', @@ -57,7 +70,7 @@ describe('api', () => { test('it calls createIncident correctly', async () => { const params = { ...apiParams, externalId: null }; - await api.pushToService({ externalService, mapping, params }); + await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); expect(externalService.createIncident).toHaveBeenCalledWith({ incident: { @@ -69,9 +82,25 @@ describe('api', () => { expect(externalService.updateIncident).not.toHaveBeenCalled(); }); + test('it calls createIncident correctly without mapping', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); + + expect(externalService.createIncident).toHaveBeenCalledWith({ + incident: { + description: 'Incident description', + summary: 'Incident title', + issueType: '10006', + labels: ['kibana', 'elastic'], + priority: 'High', + }, + }); + expect(externalService.updateIncident).not.toHaveBeenCalled(); + }); + test('it calls createComment correctly', async () => { const params = { ...apiParams, externalId: null }; - await api.pushToService({ externalService, mapping, params }); + await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); expect(externalService.createComment).toHaveBeenCalledTimes(2); expect(externalService.createComment).toHaveBeenNthCalledWith(1, { incidentId: 'incident-1', @@ -89,7 +118,6 @@ describe('api', () => { username: 'elastic', }, }, - field: 'comments', }); expect(externalService.createComment).toHaveBeenNthCalledWith(2, { @@ -108,14 +136,59 @@ describe('api', () => { username: 'elastic', }, }, - field: 'comments', + }); + }); + + test('it calls createComment correctly without mapping', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); + expect(externalService.createComment).toHaveBeenCalledTimes(2); + expect(externalService.createComment).toHaveBeenNthCalledWith(1, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-1', + comment: 'A comment', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + }, + }); + + expect(externalService.createComment).toHaveBeenNthCalledWith(2, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-2', + comment: 'Another comment', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + }, }); }); }); describe('update incident', () => { test('it updates an incident', async () => { - const res = await api.pushToService({ externalService, mapping, params: apiParams }); + const res = await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); expect(res).toEqual({ id: 'incident-1', @@ -137,7 +210,12 @@ describe('api', () => { test('it updates an incident without comments', async () => { const params = { ...apiParams, comments: [] }; - const res = await api.pushToService({ externalService, mapping, params }); + const res = await api.pushToService({ + externalService, + mapping, + params, + logger: mockedLogger, + }); expect(res).toEqual({ id: 'incident-1', @@ -149,7 +227,7 @@ describe('api', () => { test('it calls updateIncident correctly', async () => { const params = { ...apiParams }; - await api.pushToService({ externalService, mapping, params }); + await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); expect(externalService.updateIncident).toHaveBeenCalledWith({ incidentId: 'incident-3', @@ -162,9 +240,26 @@ describe('api', () => { expect(externalService.createIncident).not.toHaveBeenCalled(); }); + test('it calls updateIncident correctly without mapping', async () => { + const params = { ...apiParams }; + await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); + + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + description: 'Incident description', + summary: 'Incident title', + issueType: '10006', + labels: ['kibana', 'elastic'], + priority: 'High', + }, + }); + expect(externalService.createIncident).not.toHaveBeenCalled(); + }); + test('it calls createComment correctly', async () => { const params = { ...apiParams }; - await api.pushToService({ externalService, mapping, params }); + await api.pushToService({ externalService, mapping, params, logger: mockedLogger }); expect(externalService.createComment).toHaveBeenCalledTimes(2); expect(externalService.createComment).toHaveBeenNthCalledWith(1, { incidentId: 'incident-1', @@ -182,7 +277,6 @@ describe('api', () => { username: 'elastic', }, }, - field: 'comments', }); expect(externalService.createComment).toHaveBeenNthCalledWith(2, { @@ -201,7 +295,87 @@ describe('api', () => { username: 'elastic', }, }, - field: 'comments', + }); + }); + + test('it calls createComment correctly without mapping', async () => { + const params = { ...apiParams }; + await api.pushToService({ externalService, mapping: null, params, logger: mockedLogger }); + expect(externalService.createComment).toHaveBeenCalledTimes(2); + expect(externalService.createComment).toHaveBeenNthCalledWith(1, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-1', + comment: 'A comment', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + }, + }); + + expect(externalService.createComment).toHaveBeenNthCalledWith(2, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-2', + comment: 'Another comment', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + }, + }); + }); + }); + + describe('issueTypes', () => { + test('it returns the issue types correctly', async () => { + const res = await api.issueTypes({ + externalService, + params: {}, + }); + expect(res).toEqual([ + { + id: '10006', + name: 'Task', + }, + { + id: '10007', + name: 'Bug', + }, + ]); + }); + }); + + describe('fieldsByIssueType', () => { + test('it returns the fields correctly', async () => { + const res = await api.fieldsByIssueType({ + externalService, + params: { id: '10006' }, + }); + expect(res).toEqual({ + summary: { allowedValues: [], defaultValue: {} }, + priority: { + allowedValues: [ + { + name: 'Medium', + id: '3', + }, + ], + defaultValue: { name: 'Medium', id: '3' }, + }, }); }); }); @@ -228,7 +402,12 @@ describe('api', () => { actionType: 'overwrite', }); - await api.pushToService({ externalService, mapping, params: apiParams }); + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); expect(externalService.updateIncident).toHaveBeenCalledWith({ incidentId: 'incident-3', incident: { @@ -260,7 +439,12 @@ describe('api', () => { actionType: 'nothing', }); - await api.pushToService({ externalService, mapping, params: apiParams }); + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); expect(externalService.updateIncident).toHaveBeenCalledWith({ incidentId: 'incident-3', incident: { @@ -291,7 +475,12 @@ describe('api', () => { actionType: 'append', }); - await api.pushToService({ externalService, mapping, params: apiParams }); + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); expect(externalService.updateIncident).toHaveBeenCalledWith({ incidentId: 'incident-3', incident: { @@ -324,7 +513,12 @@ describe('api', () => { actionType: 'nothing', }); - await api.pushToService({ externalService, mapping, params: apiParams }); + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); expect(externalService.updateIncident).toHaveBeenCalledWith({ incidentId: 'incident-3', incident: {}, @@ -352,7 +546,12 @@ describe('api', () => { actionType: 'overwrite', }); - await api.pushToService({ externalService, mapping, params: apiParams }); + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); expect(externalService.updateIncident).toHaveBeenCalledWith({ incidentId: 'incident-3', incident: { @@ -382,7 +581,12 @@ describe('api', () => { actionType: 'overwrite', }); - await api.pushToService({ externalService, mapping, params: apiParams }); + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); expect(externalService.updateIncident).toHaveBeenCalledWith({ incidentId: 'incident-3', incident: { @@ -414,7 +618,12 @@ describe('api', () => { actionType: 'nothing', }); - await api.pushToService({ externalService, mapping, params: apiParams }); + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); expect(externalService.updateIncident).toHaveBeenCalledWith({ incidentId: 'incident-3', incident: { @@ -445,7 +654,12 @@ describe('api', () => { actionType: 'append', }); - await api.pushToService({ externalService, mapping, params: apiParams }); + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); expect(externalService.updateIncident).toHaveBeenCalledWith({ incidentId: 'incident-3', incident: { @@ -478,7 +692,12 @@ describe('api', () => { actionType: 'append', }); - await api.pushToService({ externalService, mapping, params: apiParams }); + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); expect(externalService.updateIncident).toHaveBeenCalledWith({ incidentId: 'incident-3', incident: { @@ -509,7 +728,12 @@ describe('api', () => { actionType: 'overwrite', }); - await api.pushToService({ externalService, mapping, params: apiParams }); + await api.pushToService({ + externalService, + mapping, + params: apiParams, + logger: mockedLogger, + }); expect(externalService.createComment).not.toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts index 3db66e5884af..da47a4bfb839 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts @@ -4,4 +4,179 @@ * you may not use this file except in compliance with the Elastic License. */ -export { api } from '../case/api'; +import { flow } from 'lodash'; +import { + ExternalServiceParams, + PushToServiceApiHandlerArgs, + HandshakeApiHandlerArgs, + GetIncidentApiHandlerArgs, + ExternalServiceApi, + Incident, + GetFieldsByIssueTypeHandlerArgs, + GetIssueTypesHandlerArgs, + PushToServiceApiParams, +} from './types'; + +// TODO: to remove, need to support Case +import { transformers } from '../case/transformers'; +import { TransformFieldsArgs, Comment, EntityInformation } from '../case/common_types'; + +import { PushToServiceResponse } from './types'; +import { prepareFieldsForTransformation } from '../case/utils'; + +const handshakeHandler = async ({ + externalService, + mapping, + params, +}: HandshakeApiHandlerArgs) => {}; + +const getIncidentHandler = async ({ + externalService, + mapping, + params, +}: GetIncidentApiHandlerArgs) => {}; + +const getIssueTypesHandler = async ({ externalService }: GetIssueTypesHandlerArgs) => { + const res = await externalService.getIssueTypes(); + return res; +}; + +const getFieldsByIssueTypeHandler = async ({ + externalService, + params, +}: GetFieldsByIssueTypeHandlerArgs) => { + const { id } = params; + const res = await externalService.getFieldsByIssueType(id); + return res; +}; + +const pushToServiceHandler = async ({ + externalService, + mapping, + params, + logger, +}: PushToServiceApiHandlerArgs): Promise => { + const { externalId, comments } = params; + const updateIncident = externalId ? true : false; + const defaultPipes = updateIncident ? ['informationUpdated'] : ['informationCreated']; + let currentIncident: ExternalServiceParams | undefined; + let res: PushToServiceResponse; + + if (externalId) { + try { + currentIncident = await externalService.getIncident(externalId); + } catch (ex) { + logger.debug( + `Retrieving Incident by id ${externalId} from Jira failed with exception: ${ex}` + ); + } + } + + let incident: Incident; + // TODO: should be removed later but currently keep it for the Case implementation support + if (mapping) { + const fields = prepareFieldsForTransformation({ + externalCase: params.externalObject, + mapping, + defaultPipes, + }); + + incident = transformFields({ + params, + fields, + currentIncident, + }); + } else { + const { title, description, priority, labels, issueType } = params; + incident = { summary: title, description, priority, labels, issueType }; + } + + if (externalId != null) { + res = await externalService.updateIncident({ + incidentId: externalId, + incident, + }); + } else { + res = await externalService.createIncident({ + incident: { + ...incident, + }, + }); + } + + if (comments && Array.isArray(comments) && comments.length > 0) { + if (mapping && mapping.get('comments')?.actionType === 'nothing') { + return res; + } + + const commentsTransformed = mapping + ? transformComments(comments, ['informationAdded']) + : comments; + + res.comments = []; + for (const currentComment of commentsTransformed) { + const comment = await externalService.createComment({ + incidentId: res.id, + comment: currentComment, + }); + res.comments = [ + ...(res.comments ?? []), + { + commentId: comment.commentId, + pushedDate: comment.pushedDate, + }, + ]; + } + } + + return res; +}; + +export const transformFields = ({ + params, + fields, + currentIncident, +}: TransformFieldsArgs): Incident => { + return fields.reduce((prev, cur) => { + const transform = flow(...cur.pipes.map((p) => transformers[p])); + return { + ...prev, + [cur.key]: transform({ + value: cur.value, + date: params.updatedAt ?? params.createdAt, + user: getEntity(params), + previousValue: currentIncident ? currentIncident[cur.key] : '', + }).value, + }; + }, {} as Incident); +}; + +export const transformComments = (comments: Comment[], pipes: string[]): Comment[] => { + return comments.map((c) => ({ + ...c, + comment: flow(...pipes.map((p) => transformers[p]))({ + value: c.comment, + date: c.updatedAt ?? c.createdAt, + user: getEntity(c), + }).value, + })); +}; + +export const getEntity = (entity: EntityInformation): string => + (entity.updatedBy != null + ? entity.updatedBy.fullName + ? entity.updatedBy.fullName + : entity.updatedBy.username + : entity.createdBy != null + ? entity.createdBy.fullName + ? entity.createdBy.fullName + : entity.createdBy.username + : '') ?? ''; + +export const api: ExternalServiceApi = { + handshake: handshakeHandler, + pushToService: pushToServiceHandler, + getIncident: getIncidentHandler, + issueTypes: getIssueTypesHandler, + fieldsByIssueType: getFieldsByIssueTypeHandler, +}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/config.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/config.ts deleted file mode 100644 index 54f28e447010..000000000000 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/config.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { ExternalServiceConfiguration } from '../case/types'; -import * as i18n from './translations'; - -export const config: ExternalServiceConfiguration = { - id: '.jira', - name: i18n.NAME, - minimumLicenseRequired: 'gold', -}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts index 66be0bad02d7..d3346557f368 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts @@ -4,33 +4,138 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Logger } from '../../../../../../src/core/server'; -import { createConnector } from '../case/utils'; -import { ActionType } from '../../types'; +import { curry } from 'lodash'; +import { schema } from '@kbn/config-schema'; -import { api } from './api'; -import { config } from './config'; import { validate } from './validators'; -import { createExternalService } from './service'; -import { JiraSecretConfiguration, JiraPublicConfiguration } from './schema'; +import { + ExternalIncidentServiceConfiguration, + ExternalIncidentServiceSecretConfiguration, + ExecutorParamsSchema, +} from './schema'; import { ActionsConfigurationUtilities } from '../../actions_config'; +import { ActionType, ActionTypeExecutorOptions, ActionTypeExecutorResult } from '../../types'; +import { createExternalService } from './service'; +import { api } from './api'; +import { + ExecutorParams, + ExecutorSubActionPushParams, + JiraPublicConfigurationType, + JiraSecretConfigurationType, + JiraExecutorResultData, + ExecutorSubActionGetFieldsByIssueTypeParams, + ExecutorSubActionGetIssueTypesParams, +} from './types'; +import * as i18n from './translations'; +import { Logger } from '../../../../../../src/core/server'; -export function getActionType({ - logger, - configurationUtilities, -}: { +// TODO: to remove, need to support Case +import { buildMap, mapParams } from '../case/utils'; + +interface GetActionTypeParams { logger: Logger; configurationUtilities: ActionsConfigurationUtilities; -}): ActionType { - return createConnector({ - api, - config, - validate, - createExternalService, - validationSchema: { - config: JiraPublicConfiguration, - secrets: JiraSecretConfiguration, +} + +const supportedSubActions: string[] = ['pushToService', 'issueTypes', 'fieldsByIssueType']; + +// action type definition +export function getActionType( + params: GetActionTypeParams +): ActionType< + JiraPublicConfigurationType, + JiraSecretConfigurationType, + ExecutorParams, + JiraExecutorResultData | {} +> { + const { logger, configurationUtilities } = params; + return { + id: '.jira', + minimumLicenseRequired: 'gold', + name: i18n.NAME, + validate: { + config: schema.object(ExternalIncidentServiceConfiguration, { + validate: curry(validate.config)(configurationUtilities), + }), + secrets: schema.object(ExternalIncidentServiceSecretConfiguration, { + validate: curry(validate.secrets)(configurationUtilities), + }), + params: ExecutorParamsSchema, + }, + executor: curry(executor)({ logger }), + }; +} + +// action executor +async function executor( + { logger }: { logger: Logger }, + execOptions: ActionTypeExecutorOptions< + JiraPublicConfigurationType, + JiraSecretConfigurationType, + ExecutorParams + > +): Promise> { + const { actionId, config, params, secrets } = execOptions; + const { subAction, subActionParams } = params as ExecutorParams; + let data: JiraExecutorResultData | null = null; + + const externalService = createExternalService( + { + config, + secrets, }, logger, - })({ configurationUtilities }); + execOptions.proxySettings + ); + + if (!api[subAction]) { + const errorMessage = `[Action][ExternalService] Unsupported subAction type ${subAction}.`; + logger.error(errorMessage); + throw new Error(errorMessage); + } + + if (!supportedSubActions.includes(subAction)) { + const errorMessage = `[Action][ExternalService] subAction ${subAction} not implemented.`; + logger.error(errorMessage); + throw new Error(errorMessage); + } + + if (subAction === 'pushToService') { + const pushToServiceParams = subActionParams as ExecutorSubActionPushParams; + + const { comments, externalId, ...restParams } = pushToServiceParams; + const incidentConfiguration = config.incidentConfiguration; + const mapping = incidentConfiguration ? buildMap(incidentConfiguration.mapping) : null; + const externalObject = + config.incidentConfiguration && mapping + ? mapParams(restParams as ExecutorSubActionPushParams, mapping) + : {}; + + data = await api.pushToService({ + externalService, + mapping, + params: { ...pushToServiceParams, externalObject }, + logger, + }); + + logger.debug(`response push to service for incident id: ${data.id}`); + } + + if (subAction === 'issueTypes') { + const getIssueTypesParams = subActionParams as ExecutorSubActionGetIssueTypesParams; + data = await api.issueTypes({ + externalService, + params: getIssueTypesParams, + }); + } + + if (subAction === 'fieldsByIssueType') { + const getFieldsByIssueTypeParams = subActionParams as ExecutorSubActionGetFieldsByIssueTypeParams; + data = await api.fieldsByIssueType({ + externalService, + params: getFieldsByIssueTypeParams, + }); + } + + return { status: 'ok', data: data ?? {}, actionId }; } diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts index 709d490a5227..e7841996fede 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts @@ -4,12 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - ExternalService, - PushToServiceApiParams, - ExecutorSubActionPushParams, - MapRecord, -} from '../case/types'; +import { ExternalService, PushToServiceApiParams, ExecutorSubActionPushParams } from './types'; + +import { MapRecord } from '../case/common_types'; const createMock = (): jest.Mocked => { const service = { @@ -40,6 +37,30 @@ const createMock = (): jest.Mocked => { }) ), createComment: jest.fn(), + findIncidents: jest.fn(), + getCapabilities: jest.fn(), + getIssueTypes: jest.fn().mockImplementation(() => [ + { + id: '10006', + name: 'Task', + }, + { + id: '10007', + name: 'Bug', + }, + ]), + getFieldsByIssueType: jest.fn().mockImplementation(() => ({ + summary: { allowedValues: [], defaultValue: {} }, + priority: { + allowedValues: [ + { + name: 'Medium', + id: '3', + }, + ], + defaultValue: { name: 'Medium', id: '3' }, + }, + })), }; service.createComment.mockImplementationOnce(() => @@ -96,6 +117,9 @@ const executorParams: ExecutorSubActionPushParams = { updatedBy: { fullName: 'Elastic User', username: 'elastic' }, title: 'Incident title', description: 'Incident description', + labels: ['kibana', 'elastic'], + priority: 'High', + issueType: '10006', comments: [ { commentId: 'case-comment-1', @@ -118,7 +142,7 @@ const executorParams: ExecutorSubActionPushParams = { const apiParams: PushToServiceApiParams = { ...executorParams, - externalCase: { summary: 'Incident title', description: 'Incident description' }, + externalObject: { summary: 'Incident title', description: 'Incident description' }, }; export { externalServiceMock, mapping, executorParams, apiParams }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts index 9c831e75d91c..07c8e22812b2 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts @@ -5,18 +5,85 @@ */ import { schema } from '@kbn/config-schema'; -import { ExternalIncidentServiceConfiguration } from '../case/schema'; +import { + CommentSchema, + EntityInformation, + IncidentConfigurationSchema, +} from '../case/common_schema'; -export const JiraPublicConfiguration = { +export const ExternalIncidentServiceConfiguration = { + apiUrl: schema.string(), projectKey: schema.string(), - ...ExternalIncidentServiceConfiguration, + // TODO: to remove - set it optional for the current stage to support Case Jira implementation + incidentConfiguration: schema.nullable(IncidentConfigurationSchema), + isCaseOwned: schema.nullable(schema.boolean()), }; -export const JiraPublicConfigurationSchema = schema.object(JiraPublicConfiguration); +export const ExternalIncidentServiceConfigurationSchema = schema.object( + ExternalIncidentServiceConfiguration +); -export const JiraSecretConfiguration = { +export const ExternalIncidentServiceSecretConfiguration = { email: schema.string(), apiToken: schema.string(), }; -export const JiraSecretConfigurationSchema = schema.object(JiraSecretConfiguration); +export const ExternalIncidentServiceSecretConfigurationSchema = schema.object( + ExternalIncidentServiceSecretConfiguration +); + +export const ExecutorSubActionSchema = schema.oneOf([ + schema.literal('getIncident'), + schema.literal('pushToService'), + schema.literal('handshake'), + schema.literal('issueTypes'), + schema.literal('fieldsByIssueType'), +]); + +export const ExecutorSubActionPushParamsSchema = schema.object({ + savedObjectId: schema.string(), + title: schema.string(), + description: schema.nullable(schema.string()), + externalId: schema.nullable(schema.string()), + issueType: schema.nullable(schema.string()), + priority: schema.nullable(schema.string()), + labels: schema.nullable(schema.arrayOf(schema.string())), + // TODO: modify later to string[] - need for support Case schema + comments: schema.nullable(schema.arrayOf(CommentSchema)), + ...EntityInformation, +}); + +export const ExecutorSubActionGetIncidentParamsSchema = schema.object({ + externalId: schema.string(), +}); + +// Reserved for future implementation +export const ExecutorSubActionHandshakeParamsSchema = schema.object({}); +export const ExecutorSubActionGetCapabilitiesParamsSchema = schema.object({}); +export const ExecutorSubActionGetIssueTypesParamsSchema = schema.object({}); +export const ExecutorSubActionGetFieldsByIssueTypeParamsSchema = schema.object({ + id: schema.string(), +}); + +export const ExecutorParamsSchema = schema.oneOf([ + schema.object({ + subAction: schema.literal('getIncident'), + subActionParams: ExecutorSubActionGetIncidentParamsSchema, + }), + schema.object({ + subAction: schema.literal('handshake'), + subActionParams: ExecutorSubActionHandshakeParamsSchema, + }), + schema.object({ + subAction: schema.literal('pushToService'), + subActionParams: ExecutorSubActionPushParamsSchema, + }), + schema.object({ + subAction: schema.literal('issueTypes'), + subActionParams: ExecutorSubActionGetIssueTypesParamsSchema, + }), + schema.object({ + subAction: schema.literal('fieldsByIssueType'), + subActionParams: ExecutorSubActionGetFieldsByIssueTypeParamsSchema, + }), +]); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts index 547595b4c183..2439c507c332 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts @@ -8,11 +8,15 @@ import axios from 'axios'; import { createExternalService } from './service'; import * as utils from '../lib/axios_utils'; -import { ExternalService } from '../case/types'; +import { ExternalService } from './types'; import { Logger } from '../../../../../../src/core/server'; import { loggingSystemMock } from '../../../../../../src/core/server/mocks'; const logger = loggingSystemMock.create().get() as jest.Mocked; +interface ResponseError extends Error { + response?: { data: { errors: Record } }; +} + jest.mock('axios'); jest.mock('../lib/axios_utils', () => { const originalUtils = jest.requireActual('../lib/axios_utils'); @@ -25,6 +29,72 @@ jest.mock('../lib/axios_utils', () => { axios.create = jest.fn(() => axios); const requestMock = utils.request as jest.Mock; +const issueTypesResponse = { + data: { + projects: [ + { + issuetypes: [ + { + id: '10006', + name: 'Task', + }, + { + id: '10007', + name: 'Bug', + }, + ], + }, + ], + }, +}; + +const fieldsResponse = { + data: { + projects: [ + { + issuetypes: [ + { + id: '10006', + name: 'Task', + fields: { + summary: { fieldId: 'summary' }, + priority: { + fieldId: 'priority', + allowedValues: [ + { + name: 'Highest', + id: '1', + }, + { + name: 'High', + id: '2', + }, + { + name: 'Medium', + id: '3', + }, + { + name: 'Low', + id: '4', + }, + { + name: 'Lowest', + id: '5', + }, + ], + defaultValue: { + name: 'Medium', + id: '3', + }, + }, + }, + }, + ], + }, + ], + }, +}; + describe('Jira service', () => { let service: ExternalService; @@ -116,19 +186,24 @@ describe('Jira service', () => { test('it should throw an error', async () => { requestMock.mockImplementation(() => { - throw new Error('An error has occurred'); + const error: ResponseError = new Error('An error has occurred'); + error.response = { data: { errors: { summary: 'Required field' } } }; + throw error; }); expect(service.getIncident('1')).rejects.toThrow( - 'Unable to get incident with id 1. Error: An error has occurred' + '[Action][Jira]: Unable to get incident with id 1. Error: An error has occurred Reason: Required field' ); }); }); describe('createIncident', () => { test('it creates the incident correctly', async () => { - // The response from Jira when creating an issue contains only the key and the id. - // The service makes two calls when creating an issue. One to create and one to get - // the created incident with all the necessary fields. + /* The response from Jira when creating an issue contains only the key and the id. + The function makes the following calls when creating an issue: + 1. Get issueTypes to set a default ONLY when incident.issueType is missing + 2. Create the issue. + 3. Get the created issue with all the necessary fields. + */ requestMock.mockImplementationOnce(() => ({ data: { id: '1', key: 'CK-1', fields: { summary: 'title', description: 'description' } }, })); @@ -138,7 +213,13 @@ describe('Jira service', () => { })); const res = await service.createIncident({ - incident: { summary: 'title', description: 'desc' }, + incident: { + summary: 'title', + description: 'desc', + labels: [], + issueType: '10006', + priority: 'High', + }, }); expect(res).toEqual({ @@ -149,6 +230,68 @@ describe('Jira service', () => { }); }); + test('it creates the incident correctly without issue type', async () => { + /* The response from Jira when creating an issue contains only the key and the id. + The function makes the following calls when creating an issue: + 1. Get issueTypes to set a default ONLY when incident.issueType is missing + 2. Create the issue. + 3. Get the created issue with all the necessary fields. + */ + // getIssueType mocks + requestMock.mockImplementationOnce(() => ({ + data: { + capabilities: { + navigation: 'https://siem-kibana.atlassian.net/rest/capabilities/navigation', + }, + }, + })); + + // getIssueType mocks + requestMock.mockImplementationOnce(() => issueTypesResponse); + + requestMock.mockImplementationOnce(() => ({ + data: { id: '1', key: 'CK-1', fields: { summary: 'title', description: 'description' } }, + })); + + requestMock.mockImplementationOnce(() => ({ + data: { id: '1', key: 'CK-1', fields: { created: '2020-04-27T10:59:46.202Z' } }, + })); + + const res = await service.createIncident({ + incident: { + summary: 'title', + description: 'desc', + labels: [], + priority: 'High', + issueType: null, + }, + }); + + expect(res).toEqual({ + title: 'CK-1', + id: '1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', + }); + + expect(requestMock).toHaveBeenCalledWith({ + axios, + url: 'https://siem-kibana.atlassian.net/rest/api/2/issue', + logger, + method: 'post', + data: { + fields: { + summary: 'title', + description: 'desc', + project: { key: 'CK' }, + issuetype: { id: '10006' }, + labels: [], + priority: { name: 'High' }, + }, + }, + }); + }); + test('it should call request with correct arguments', async () => { requestMock.mockImplementation(() => ({ data: { @@ -159,7 +302,13 @@ describe('Jira service', () => { })); await service.createIncident({ - incident: { summary: 'title', description: 'desc' }, + incident: { + summary: 'title', + description: 'desc', + labels: [], + issueType: '10006', + priority: 'High', + }, }); expect(requestMock).toHaveBeenCalledWith({ @@ -172,7 +321,9 @@ describe('Jira service', () => { summary: 'title', description: 'desc', project: { key: 'CK' }, - issuetype: { name: 'Task' }, + issuetype: { id: '10006' }, + labels: [], + priority: { name: 'High' }, }, }, }); @@ -180,14 +331,24 @@ describe('Jira service', () => { test('it should throw an error', async () => { requestMock.mockImplementation(() => { - throw new Error('An error has occurred'); + const error: ResponseError = new Error('An error has occurred'); + error.response = { data: { errors: { summary: 'Required field' } } }; + throw error; }); expect( service.createIncident({ - incident: { summary: 'title', description: 'desc' }, + incident: { + summary: 'title', + description: 'desc', + labels: [], + issueType: '10006', + priority: 'High', + }, }) - ).rejects.toThrow('[Action][Jira]: Unable to create incident. Error: An error has occurred'); + ).rejects.toThrow( + '[Action][Jira]: Unable to create incident. Error: An error has occurred. Reason: Required field' + ); }); }); @@ -203,7 +364,13 @@ describe('Jira service', () => { const res = await service.updateIncident({ incidentId: '1', - incident: { summary: 'title', description: 'desc' }, + incident: { + summary: 'title', + description: 'desc', + labels: [], + issueType: '10006', + priority: 'High', + }, }); expect(res).toEqual({ @@ -225,7 +392,13 @@ describe('Jira service', () => { await service.updateIncident({ incidentId: '1', - incident: { summary: 'title', description: 'desc' }, + incident: { + summary: 'title', + description: 'desc', + labels: [], + issueType: '10006', + priority: 'High', + }, }); expect(requestMock).toHaveBeenCalledWith({ @@ -233,22 +406,39 @@ describe('Jira service', () => { logger, method: 'put', url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/1', - data: { fields: { summary: 'title', description: 'desc' } }, + data: { + fields: { + summary: 'title', + description: 'desc', + labels: [], + priority: { name: 'High' }, + issuetype: { id: '10006' }, + project: { key: 'CK' }, + }, + }, }); }); test('it should throw an error', async () => { requestMock.mockImplementation(() => { - throw new Error('An error has occurred'); + const error: ResponseError = new Error('An error has occurred'); + error.response = { data: { errors: { summary: 'Required field' } } }; + throw error; }); expect( service.updateIncident({ incidentId: '1', - incident: { summary: 'title', description: 'desc' }, + incident: { + summary: 'title', + description: 'desc', + labels: [], + issueType: '10006', + priority: 'High', + }, }) ).rejects.toThrow( - '[Action][Jira]: Unable to update incident with id 1. Error: An error has occurred' + '[Action][Jira]: Unable to update incident with id 1. Error: An error has occurred. Reason: Required field' ); }); }); @@ -265,8 +455,14 @@ describe('Jira service', () => { const res = await service.createComment({ incidentId: '1', - comment: { comment: 'comment', commentId: 'comment-1' }, - field: 'comments', + comment: { + comment: 'comment', + commentId: 'comment-1', + createdBy: null, + createdAt: null, + updatedAt: null, + updatedBy: null, + }, }); expect(res).toEqual({ @@ -287,8 +483,14 @@ describe('Jira service', () => { await service.createComment({ incidentId: '1', - comment: { comment: 'comment', commentId: 'comment-1' }, - field: 'my_field', + comment: { + comment: 'comment', + commentId: 'comment-1', + createdBy: null, + createdAt: null, + updatedAt: null, + updatedBy: null, + }, }); expect(requestMock).toHaveBeenCalledWith({ @@ -302,18 +504,416 @@ describe('Jira service', () => { test('it should throw an error', async () => { requestMock.mockImplementation(() => { - throw new Error('An error has occurred'); + const error: ResponseError = new Error('An error has occurred'); + error.response = { data: { errors: { summary: 'Required field' } } }; + throw error; }); expect( service.createComment({ incidentId: '1', - comment: { comment: 'comment', commentId: 'comment-1' }, - field: 'comments', + comment: { + comment: 'comment', + commentId: 'comment-1', + createdBy: null, + createdAt: null, + updatedAt: null, + updatedBy: null, + }, }) ).rejects.toThrow( - '[Action][Jira]: Unable to create comment at incident with id 1. Error: An error has occurred' + '[Action][Jira]: Unable to create comment at incident with id 1. Error: An error has occurred. Reason: Required field' + ); + }); + }); + + describe('getCapabilities', () => { + test('it should return the capabilities', async () => { + requestMock.mockImplementation(() => ({ + data: { + capabilities: { + navigation: 'https://siem-kibana.atlassian.net/rest/capabilities/navigation', + }, + }, + })); + const res = await service.getCapabilities(); + expect(res).toEqual({ + capabilities: { + navigation: 'https://siem-kibana.atlassian.net/rest/capabilities/navigation', + }, + }); + }); + + test('it should call request with correct arguments', async () => { + requestMock.mockImplementation(() => ({ + data: { + capabilities: { + navigation: 'https://siem-kibana.atlassian.net/rest/capabilities/navigation', + }, + }, + })); + + await service.getCapabilities(); + + expect(requestMock).toHaveBeenCalledWith({ + axios, + logger, + method: 'get', + url: 'https://siem-kibana.atlassian.net/rest/capabilities', + }); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementation(() => { + const error: ResponseError = new Error('An error has occurred'); + error.response = { data: { errors: { capabilities: 'Could not get capabilities' } } }; + throw error; + }); + + expect(service.getCapabilities()).rejects.toThrow( + '[Action][Jira]: Unable to get capabilities. Error: An error has occurred. Reason: Could not get capabilities' ); }); }); + + describe('getIssueTypes', () => { + describe('Old API', () => { + test('it should return the issue types', async () => { + requestMock.mockImplementationOnce(() => ({ + data: { + capabilities: { + navigation: 'https://siem-kibana.atlassian.net/rest/capabilities/navigation', + }, + }, + })); + + requestMock.mockImplementationOnce(() => issueTypesResponse); + + const res = await service.getIssueTypes(); + + expect(res).toEqual([ + { + id: '10006', + name: 'Task', + }, + { + id: '10007', + name: 'Bug', + }, + ]); + }); + + test('it should call request with correct arguments', async () => { + requestMock.mockImplementationOnce(() => ({ + data: { + capabilities: { + navigation: 'https://siem-kibana.atlassian.net/rest/capabilities/navigation', + }, + }, + })); + + requestMock.mockImplementationOnce(() => issueTypesResponse); + + await service.getIssueTypes(); + + expect(requestMock).toHaveBeenLastCalledWith({ + axios, + logger, + method: 'get', + url: + 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta?projectKeys=CK&expand=projects.issuetypes.fields', + }); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementationOnce(() => ({ + data: { + capabilities: { + navigation: 'https://siem-kibana.atlassian.net/rest/capabilities/navigation', + }, + }, + })); + + requestMock.mockImplementation(() => { + const error: ResponseError = new Error('An error has occurred'); + error.response = { data: { errors: { issuetypes: 'Could not get issue types' } } }; + throw error; + }); + + expect(service.getIssueTypes()).rejects.toThrow( + '[Action][Jira]: Unable to get issue types. Error: An error has occurred. Reason: Could not get issue types' + ); + }); + }); + describe('New API', () => { + test('it should return the issue types', async () => { + requestMock.mockImplementationOnce(() => ({ + data: { + capabilities: { + 'list-project-issuetypes': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes', + 'list-issuetype-fields': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields', + }, + }, + })); + + requestMock.mockImplementationOnce(() => ({ + data: { + values: issueTypesResponse.data.projects[0].issuetypes, + }, + })); + + const res = await service.getIssueTypes(); + + expect(res).toEqual([ + { + id: '10006', + name: 'Task', + }, + { + id: '10007', + name: 'Bug', + }, + ]); + }); + + test('it should call request with correct arguments', async () => { + requestMock.mockImplementationOnce(() => ({ + data: { + capabilities: { + 'list-project-issuetypes': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes', + 'list-issuetype-fields': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields', + }, + }, + })); + + requestMock.mockImplementationOnce(() => ({ + data: { + values: issueTypesResponse.data.projects[0].issuetypes, + }, + })); + + await service.getIssueTypes(); + + expect(requestMock).toHaveBeenLastCalledWith({ + axios, + logger, + method: 'get', + url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes', + }); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementationOnce(() => ({ + data: { + capabilities: { + 'list-project-issuetypes': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes', + 'list-issuetype-fields': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields', + }, + }, + })); + + requestMock.mockImplementation(() => { + const error: ResponseError = new Error('An error has occurred'); + error.response = { data: { errors: { issuetypes: 'Could not get issue types' } } }; + throw error; + }); + + expect(service.getIssueTypes()).rejects.toThrow( + '[Action][Jira]: Unable to get issue types. Error: An error has occurred. Reason: Could not get issue types' + ); + }); + }); + }); + + describe('getFieldsByIssueType', () => { + describe('Old API', () => { + test('it should return the fields', async () => { + requestMock.mockImplementationOnce(() => ({ + data: { + capabilities: { + navigation: 'https://siem-kibana.atlassian.net/rest/capabilities/navigation', + }, + }, + })); + + requestMock.mockImplementationOnce(() => fieldsResponse); + + const res = await service.getFieldsByIssueType('10006'); + + expect(res).toEqual({ + priority: { + allowedValues: [ + { id: '1', name: 'Highest' }, + { id: '2', name: 'High' }, + { id: '3', name: 'Medium' }, + { id: '4', name: 'Low' }, + { id: '5', name: 'Lowest' }, + ], + defaultValue: { id: '3', name: 'Medium' }, + }, + summary: { allowedValues: [], defaultValue: {} }, + }); + }); + + test('it should call request with correct arguments', async () => { + requestMock.mockImplementationOnce(() => ({ + data: { + capabilities: { + navigation: 'https://siem-kibana.atlassian.net/rest/capabilities/navigation', + }, + }, + })); + + requestMock.mockImplementationOnce(() => fieldsResponse); + + await service.getFieldsByIssueType('10006'); + + expect(requestMock).toHaveBeenLastCalledWith({ + axios, + logger, + method: 'get', + url: + 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta?projectKeys=CK&issuetypeIds=10006&expand=projects.issuetypes.fields', + }); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementationOnce(() => ({ + data: { + capabilities: { + navigation: 'https://siem-kibana.atlassian.net/rest/capabilities/navigation', + }, + }, + })); + + requestMock.mockImplementation(() => { + const error: ResponseError = new Error('An error has occurred'); + error.response = { data: { errors: { fields: 'Could not get fields' } } }; + throw error; + }); + + expect(service.getFieldsByIssueType('10006')).rejects.toThrow( + '[Action][Jira]: Unable to get fields. Error: An error has occurred. Reason: Could not get fields' + ); + }); + }); + + describe('New API', () => { + test('it should return the fields', async () => { + requestMock.mockImplementationOnce(() => ({ + data: { + capabilities: { + 'list-project-issuetypes': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes', + 'list-issuetype-fields': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields', + }, + }, + })); + + requestMock.mockImplementationOnce(() => ({ + data: { + values: [ + { fieldId: 'summary' }, + { + fieldId: 'priority', + allowedValues: [ + { + name: 'Medium', + id: '3', + }, + ], + defaultValue: { + name: 'Medium', + id: '3', + }, + }, + ], + }, + })); + + const res = await service.getFieldsByIssueType('10006'); + + expect(res).toEqual({ + priority: { + allowedValues: [{ id: '3', name: 'Medium' }], + defaultValue: { id: '3', name: 'Medium' }, + }, + summary: { allowedValues: [], defaultValue: {} }, + }); + }); + + test('it should call request with correct arguments', async () => { + requestMock.mockImplementationOnce(() => ({ + data: { + capabilities: { + 'list-project-issuetypes': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes', + 'list-issuetype-fields': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields', + }, + }, + })); + + requestMock.mockImplementationOnce(() => ({ + data: { + values: [ + { fieldId: 'summary' }, + { + fieldId: 'priority', + allowedValues: [ + { + name: 'Medium', + id: '3', + }, + ], + defaultValue: { + name: 'Medium', + id: '3', + }, + }, + ], + }, + })); + + await service.getFieldsByIssueType('10006'); + + expect(requestMock).toHaveBeenLastCalledWith({ + axios, + logger, + method: 'get', + url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/createmeta/CK/issuetypes/10006', + }); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementationOnce(() => ({ + data: { + capabilities: { + 'list-project-issuetypes': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-project-issuetypes', + 'list-issuetype-fields': + 'https://siem-kibana.atlassian.net/rest/capabilities/list-issuetype-fields', + }, + }, + })); + + requestMock.mockImplementation(() => { + const error: ResponseError = new Error('An error has occurred'); + error.response = { data: { errors: { issuetypes: 'Could not get issue types' } } }; + throw error; + }); + + expect(service.getFieldsByIssueType('10006')).rejects.toThrow( + '[Action][Jira]: Unable to get fields. Error: An error has occurred. Reason: Could not get issue types' + ); + }); + }); + }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts index aec73cfb375e..84b6e70d2a10 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts @@ -6,14 +6,20 @@ import axios from 'axios'; -import { ExternalServiceCredentials, ExternalService, ExternalServiceParams } from '../case/types'; import { Logger } from '../../../../../../src/core/server'; import { + ExternalServiceCredentials, + ExternalService, + CreateIncidentParams, + UpdateIncidentParams, JiraPublicConfigurationType, JiraSecretConfigurationType, - CreateIncidentRequest, - UpdateIncidentRequest, - CreateCommentRequest, + Fields, + CreateCommentParams, + Incident, + ResponseError, + ExternalServiceCommentResponse, + ExternalServiceIncidentResponse, } from './types'; import * as i18n from './translations'; @@ -22,11 +28,12 @@ import { ProxySettings } from '../../types'; const VERSION = '2'; const BASE_URL = `rest/api/${VERSION}`; -const INCIDENT_URL = `issue`; -const COMMENT_URL = `comment`; +const CAPABILITIES_URL = `rest/capabilities`; const VIEW_INCIDENT_URL = `browse`; +const createMetaCapabilities = ['list-project-issuetypes', 'list-issuetype-fields']; + export const createExternalService = ( { config, secrets }: ExternalServiceCredentials, logger: Logger, @@ -39,8 +46,13 @@ export const createExternalService = ( throw Error(`[Action]${i18n.NAME}: Wrong configuration.`); } - const incidentUrl = `${url}/${BASE_URL}/${INCIDENT_URL}`; - const commentUrl = `${incidentUrl}/{issueId}/${COMMENT_URL}`; + const incidentUrl = `${url}/${BASE_URL}/issue`; + const capabilitiesUrl = `${url}/${CAPABILITIES_URL}`; + const commentUrl = `${incidentUrl}/{issueId}/comment`; + const getIssueTypesOldAPIURL = `${url}/${BASE_URL}/issue/createmeta?projectKeys=${projectKey}&expand=projects.issuetypes.fields`; + const getIssueTypeFieldsOldAPIURL = `${url}/${BASE_URL}/issue/createmeta?projectKeys=${projectKey}&issuetypeIds={issueTypeId}&expand=projects.issuetypes.fields`; + const getIssueTypesUrl = `${url}/${BASE_URL}/issue/createmeta/${projectKey}/issuetypes`; + const getIssueTypeFieldsUrl = `${url}/${BASE_URL}/issue/createmeta/${projectKey}/issuetypes/{issueTypeId}`; const axiosInstance = axios.create({ auth: { username: email, password: apiToken }, }); @@ -52,6 +64,60 @@ export const createExternalService = ( const getCommentsURL = (issueId: string) => { return commentUrl.replace('{issueId}', issueId); }; + const createGetIssueTypeFieldsUrl = (uri: string, issueTypeId: string) => { + return uri.replace('{issueTypeId}', issueTypeId); + }; + + const createFields = (key: string, incident: Incident): Fields => { + let fields: Fields = { + summary: incident.summary, + project: { key }, + }; + + if (incident.issueType) { + fields = { ...fields, issuetype: { id: incident.issueType } }; + } + + if (incident.description) { + fields = { ...fields, description: incident.description }; + } + + if (incident.labels) { + fields = { ...fields, labels: incident.labels }; + } + + if (incident.priority) { + fields = { ...fields, priority: { name: incident.priority } }; + } + + return fields; + }; + + const createErrorMessage = (errors: ResponseError) => { + return Object.entries(errors).reduce((errorMessage, [, value]) => { + const msg = errorMessage.length > 0 ? `${errorMessage} ${value}` : value; + return msg; + }, ''); + }; + + const hasSupportForNewAPI = (capabilities: { capabilities?: {} }) => + createMetaCapabilities.every((c) => Object.keys(capabilities?.capabilities ?? {}).includes(c)); + + const normalizeIssueTypes = (issueTypes: Array<{ id: string; name: string }>) => + issueTypes.map((type) => ({ id: type.id, name: type.name })); + + const normalizeFields = (fields: { + [key: string]: { allowedValues?: Array<{}>; defaultValue?: {} }; + }) => + Object.keys(fields ?? {}).reduce((fieldsAcc, fieldKey) => { + return { + ...fieldsAcc, + [fieldKey]: { + allowedValues: fields[fieldKey]?.allowedValues ?? [], + defaultValue: fields[fieldKey]?.defaultValue ?? {}, + }, + }; + }, {}); const getIncident = async (id: string) => { try { @@ -67,23 +133,46 @@ export const createExternalService = ( return { ...rest, ...fields }; } catch (error) { throw new Error( - getErrorMessage(i18n.NAME, `Unable to get incident with id ${id}. Error: ${error.message}`) + getErrorMessage( + i18n.NAME, + `Unable to get incident with id ${id}. Error: ${ + error.message + } Reason: ${createErrorMessage(error.response?.data?.errors ?? {})}` + ) ); } }; - const createIncident = async ({ incident }: ExternalServiceParams) => { - // The response from Jira when creating an issue contains only the key and the id. - // The function makes two calls when creating an issue. One to create the issue and one to get - // the created issue with all the necessary fields. + const createIncident = async ({ + incident, + }: CreateIncidentParams): Promise => { + /* The response from Jira when creating an issue contains only the key and the id. + The function makes the following calls when creating an issue: + 1. Get issueTypes to set a default ONLY when incident.issueType is missing + 2. Create the issue. + 3. Get the created issue with all the necessary fields. + */ + + let issueType = incident.issueType; + + if (!incident.issueType) { + const issueTypes = await getIssueTypes(); + issueType = issueTypes[0]?.id ?? ''; + } + + const fields = createFields(projectKey, { + ...incident, + issueType, + }); + try { - const res = await request({ + const res = await request({ axios: axiosInstance, url: `${incidentUrl}`, logger, method: 'post', data: { - fields: { ...incident, project: { key: projectKey }, issuetype: { name: 'Task' } }, + fields, }, proxySettings, }); @@ -98,23 +187,38 @@ export const createExternalService = ( }; } catch (error) { throw new Error( - getErrorMessage(i18n.NAME, `Unable to create incident. Error: ${error.message}`) + getErrorMessage( + i18n.NAME, + `Unable to create incident. Error: ${error.message}. Reason: ${createErrorMessage( + error.response?.data?.errors ?? {} + )}` + ) ); } }; - const updateIncident = async ({ incidentId, incident }: ExternalServiceParams) => { + const updateIncident = async ({ + incidentId, + incident, + }: UpdateIncidentParams): Promise => { + const incidentWithoutNullValues = Object.entries(incident).reduce( + (obj, [key, value]) => (value != null ? { ...obj, [key]: value } : obj), + {} as Incident + ); + + const fields = createFields(projectKey, incidentWithoutNullValues); + try { - await request({ + await request({ axios: axiosInstance, method: 'put', url: `${incidentUrl}/${incidentId}`, logger, - data: { fields: { ...incident } }, + data: { fields }, proxySettings, }); - const updatedIncident = await getIncident(incidentId); + const updatedIncident = await getIncident(incidentId as string); return { title: updatedIncident.key, @@ -126,15 +230,20 @@ export const createExternalService = ( throw new Error( getErrorMessage( i18n.NAME, - `Unable to update incident with id ${incidentId}. Error: ${error.message}` + `Unable to update incident with id ${incidentId}. Error: ${ + error.message + }. Reason: ${createErrorMessage(error.response?.data?.errors ?? {})}` ) ); } }; - const createComment = async ({ incidentId, comment, field }: ExternalServiceParams) => { + const createComment = async ({ + incidentId, + comment, + }: CreateCommentParams): Promise => { try { - const res = await request({ + const res = await request({ axios: axiosInstance, method: 'post', url: getCommentsURL(incidentId), @@ -152,7 +261,118 @@ export const createExternalService = ( throw new Error( getErrorMessage( i18n.NAME, - `Unable to create comment at incident with id ${incidentId}. Error: ${error.message}` + `Unable to create comment at incident with id ${incidentId}. Error: ${ + error.message + }. Reason: ${createErrorMessage(error.response?.data?.errors ?? {})}` + ) + ); + } + }; + + const getCapabilities = async () => { + try { + const res = await request({ + axios: axiosInstance, + method: 'get', + url: capabilitiesUrl, + logger, + proxySettings, + }); + + return { ...res.data }; + } catch (error) { + throw new Error( + getErrorMessage( + i18n.NAME, + `Unable to get capabilities. Error: ${error.message}. Reason: ${createErrorMessage( + error.response?.data?.errors ?? {} + )}` + ) + ); + } + }; + + const getIssueTypes = async () => { + const capabilitiesResponse = await getCapabilities(); + const supportsNewAPI = hasSupportForNewAPI(capabilitiesResponse); + + try { + if (!supportsNewAPI) { + const res = await request({ + axios: axiosInstance, + method: 'get', + url: getIssueTypesOldAPIURL, + logger, + proxySettings, + }); + + const issueTypes = res.data.projects[0]?.issuetypes ?? []; + return normalizeIssueTypes(issueTypes); + } else { + const res = await request({ + axios: axiosInstance, + method: 'get', + url: getIssueTypesUrl, + logger, + proxySettings, + }); + + const issueTypes = res.data.values; + return normalizeIssueTypes(issueTypes); + } + } catch (error) { + throw new Error( + getErrorMessage( + i18n.NAME, + `Unable to get issue types. Error: ${error.message}. Reason: ${createErrorMessage( + error.response?.data?.errors ?? {} + )}` + ) + ); + } + }; + + const getFieldsByIssueType = async (issueTypeId: string) => { + const capabilitiesResponse = await getCapabilities(); + const supportsNewAPI = hasSupportForNewAPI(capabilitiesResponse); + + try { + if (!supportsNewAPI) { + const res = await request({ + axios: axiosInstance, + method: 'get', + url: createGetIssueTypeFieldsUrl(getIssueTypeFieldsOldAPIURL, issueTypeId), + logger, + proxySettings, + }); + + const fields = res.data.projects[0]?.issuetypes[0]?.fields || {}; + return normalizeFields(fields); + } else { + const res = await request({ + axios: axiosInstance, + method: 'get', + url: createGetIssueTypeFieldsUrl(getIssueTypeFieldsUrl, issueTypeId), + logger, + proxySettings, + }); + + const fields = res.data.values.reduce( + (acc: { [x: string]: {} }, value: { fieldId: string }) => ({ + ...acc, + [value.fieldId]: { ...value }, + }), + {} + ); + return normalizeFields(fields); + } + } catch (error) { + throw new Error( + getErrorMessage( + i18n.NAME, + `Unable to get fields. Error: ${error.message}. Reason: ${createErrorMessage( + error.response?.data?.errors ?? {} + )}` ) ); } @@ -163,5 +383,8 @@ export const createExternalService = ( createIncident, updateIncident, createComment, + getCapabilities, + getIssueTypes, + getFieldsByIssueType, }; }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/translations.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/translations.ts index dae0d75952e1..0e71de813eb5 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/translations.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/translations.ts @@ -9,3 +9,19 @@ import { i18n } from '@kbn/i18n'; export const NAME = i18n.translate('xpack.actions.builtin.case.jiraTitle', { defaultMessage: 'Jira', }); + +export const ALLOWED_HOSTS_ERROR = (message: string) => + i18n.translate('xpack.actions.builtin.jira.configuration.apiAllowedHostsError', { + defaultMessage: 'error configuring connector action: {message}', + values: { + message, + }, + }); + +// TODO: remove when Case mappings will be removed +export const MAPPING_EMPTY = i18n.translate( + 'xpack.actions.builtin.jira.configuration.emptyMapping', + { + defaultMessage: '[incidentConfiguration.mapping]: expected non-empty but got empty', + } +); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts index 8d9c6b92abb3..5e97f5309f8e 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts @@ -4,29 +4,169 @@ * you may not use this file except in compliance with the Elastic License. */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import { TypeOf } from '@kbn/config-schema'; -import { JiraPublicConfigurationSchema, JiraSecretConfigurationSchema } from './schema'; +import { + ExternalIncidentServiceConfigurationSchema, + ExternalIncidentServiceSecretConfigurationSchema, + ExecutorParamsSchema, + ExecutorSubActionPushParamsSchema, + ExecutorSubActionGetIncidentParamsSchema, + ExecutorSubActionHandshakeParamsSchema, + ExecutorSubActionGetCapabilitiesParamsSchema, + ExecutorSubActionGetIssueTypesParamsSchema, + ExecutorSubActionGetFieldsByIssueTypeParamsSchema, +} from './schema'; +import { ActionsConfigurationUtilities } from '../../actions_config'; +import { IncidentConfigurationSchema } from '../case/common_schema'; +import { Comment } from '../case/common_types'; +import { Logger } from '../../../../../../src/core/server'; + +export type JiraPublicConfigurationType = TypeOf; +export type JiraSecretConfigurationType = TypeOf< + typeof ExternalIncidentServiceSecretConfigurationSchema +>; + +export type ExecutorParams = TypeOf; +export type ExecutorSubActionPushParams = TypeOf; + +export type IncidentConfiguration = TypeOf; + +export interface ExternalServiceCredentials { + config: Record; + secrets: Record; +} + +export interface ExternalServiceValidation { + config: (configurationUtilities: ActionsConfigurationUtilities, configObject: any) => void; + secrets: (configurationUtilities: ActionsConfigurationUtilities, secrets: any) => void; +} + +export interface ExternalServiceIncidentResponse { + id: string; + title: string; + url: string; + pushedDate: string; +} + +export interface ExternalServiceCommentResponse { + commentId: string; + pushedDate: string; + externalCommentId?: string; +} + +export type ExternalServiceParams = Record; + +export type Incident = Pick< + ExecutorSubActionPushParams, + 'description' | 'priority' | 'labels' | 'issueType' +> & { summary: string }; + +export interface CreateIncidentParams { + incident: Incident; +} + +export interface UpdateIncidentParams { + incidentId: string; + incident: Incident; +} + +export interface CreateCommentParams { + incidentId: string; + comment: Comment; +} -export type JiraPublicConfigurationType = TypeOf; -export type JiraSecretConfigurationType = TypeOf; +export type GetIssueTypesResponse = Array<{ id: string; name: string }>; +export type GetFieldsByIssueTypeResponse = Record< + string, + { allowedValues: Array<{}>; defaultValue: {} } +>; -interface CreateIncidentBasicRequestArgs { - summary: string; - description: string; +export interface ExternalService { + getIncident: (id: string) => Promise; + createIncident: (params: CreateIncidentParams) => Promise; + updateIncident: (params: UpdateIncidentParams) => Promise; + createComment: (params: CreateCommentParams) => Promise; + getCapabilities: () => Promise; + getIssueTypes: () => Promise; + getFieldsByIssueType: (issueTypeId: string) => Promise; } -interface CreateIncidentRequestArgs extends CreateIncidentBasicRequestArgs { - project: { key: string }; - issuetype: { name: string }; + +export interface PushToServiceApiParams extends ExecutorSubActionPushParams { + externalObject: Record; +} + +export type ExecutorSubActionGetIncidentParams = TypeOf< + typeof ExecutorSubActionGetIncidentParamsSchema +>; + +export type ExecutorSubActionHandshakeParams = TypeOf< + typeof ExecutorSubActionHandshakeParamsSchema +>; + +export type ExecutorSubActionGetCapabilitiesParams = TypeOf< + typeof ExecutorSubActionGetCapabilitiesParamsSchema +>; + +export type ExecutorSubActionGetIssueTypesParams = TypeOf< + typeof ExecutorSubActionGetIssueTypesParamsSchema +>; + +export type ExecutorSubActionGetFieldsByIssueTypeParams = TypeOf< + typeof ExecutorSubActionGetFieldsByIssueTypeParamsSchema +>; + +export interface ExternalServiceApiHandlerArgs { + externalService: ExternalService; + mapping: Map | null; +} + +export interface PushToServiceApiHandlerArgs extends ExternalServiceApiHandlerArgs { + params: PushToServiceApiParams; + logger: Logger; } -export interface CreateIncidentRequest { - fields: CreateIncidentRequestArgs; +export interface GetIncidentApiHandlerArgs extends ExternalServiceApiHandlerArgs { + params: ExecutorSubActionGetIncidentParams; } -export interface UpdateIncidentRequest { - fields: Partial; +export interface HandshakeApiHandlerArgs extends ExternalServiceApiHandlerArgs { + params: ExecutorSubActionHandshakeParams; } -export interface CreateCommentRequest { - body: string; +export interface GetIssueTypesHandlerArgs { + externalService: ExternalService; + params: ExecutorSubActionGetIssueTypesParams; +} + +export interface GetFieldsByIssueTypeHandlerArgs { + externalService: ExternalService; + params: ExecutorSubActionGetFieldsByIssueTypeParams; +} + +export interface PushToServiceResponse extends ExternalServiceIncidentResponse { + comments?: ExternalServiceCommentResponse[]; +} + +export interface ExternalServiceApi { + handshake: (args: HandshakeApiHandlerArgs) => Promise; + pushToService: (args: PushToServiceApiHandlerArgs) => Promise; + getIncident: (args: GetIncidentApiHandlerArgs) => Promise; + issueTypes: (args: GetIssueTypesHandlerArgs) => Promise; + fieldsByIssueType: ( + args: GetFieldsByIssueTypeHandlerArgs + ) => Promise; +} + +export type JiraExecutorResultData = + | PushToServiceResponse + | GetIssueTypesResponse + | GetFieldsByIssueTypeResponse; + +export interface Fields { + [key: string]: string | string[] | { name: string } | { key: string } | { id: string }; +} +export interface ResponseError { + [k: string]: string; } diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/validators.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/validators.ts index 7226071392bc..58a3e27247fa 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/jira/validators.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/validators.ts @@ -4,8 +4,38 @@ * you may not use this file except in compliance with the Elastic License. */ -import { validateCommonConfig, validateCommonSecrets } from '../case/validators'; -import { ExternalServiceValidation } from '../case/types'; +import { isEmpty } from 'lodash'; +import { ActionsConfigurationUtilities } from '../../actions_config'; +import { + JiraPublicConfigurationType, + JiraSecretConfigurationType, + ExternalServiceValidation, +} from './types'; + +import * as i18n from './translations'; + +export const validateCommonConfig = ( + configurationUtilities: ActionsConfigurationUtilities, + configObject: JiraPublicConfigurationType +) => { + if ( + configObject.incidentConfiguration !== null && + isEmpty(configObject.incidentConfiguration.mapping) + ) { + return i18n.MAPPING_EMPTY; + } + + try { + configurationUtilities.ensureUriAllowed(configObject.apiUrl); + } catch (allowedListError) { + return i18n.ALLOWED_HOSTS_ERROR(allowedListError.message); + } +}; + +export const validateCommonSecrets = ( + configurationUtilities: ActionsConfigurationUtilities, + secrets: JiraSecretConfigurationType +) => {}; export const validate: ExternalServiceValidation = { config: validateCommonConfig, diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts index 0bb096ecd0f6..7a68781bb9a7 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts @@ -91,7 +91,7 @@ describe('api', () => { expect(externalService.updateIncident).not.toHaveBeenCalled(); }); - test('it calls updateIncident correctly', async () => { + test('it calls updateIncident correctly when creating an incident and having comments', async () => { const params = { ...apiParams, externalId: null }; await api.pushToService({ externalService, @@ -103,7 +103,7 @@ describe('api', () => { expect(externalService.updateIncident).toHaveBeenCalledTimes(2); expect(externalService.updateIncident).toHaveBeenNthCalledWith(1, { incident: { - comments: 'A comment', + comments: 'A comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', description: 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', short_description: @@ -114,7 +114,7 @@ describe('api', () => { expect(externalService.updateIncident).toHaveBeenNthCalledWith(2, { incident: { - comments: 'Another comment', + comments: 'Another comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', description: 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', short_description: @@ -215,7 +215,7 @@ describe('api', () => { expect(externalService.updateIncident).toHaveBeenNthCalledWith(2, { incident: { - comments: 'A comment', + comments: 'A comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', description: 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', short_description: diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts index 328183294155..c8e6147ecef4 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts @@ -10,11 +10,13 @@ import { HandshakeApiHandlerArgs, GetIncidentApiHandlerArgs, ExternalServiceApi, + PushToServiceApiParams, + PushToServiceResponse, } from './types'; // TODO: to remove, need to support Case import { transformers } from '../case/transformers'; -import { PushToServiceResponse, TransformFieldsArgs } from './case_types'; +import { TransformFieldsArgs, Comment, EntityInformation } from '../case/common_types'; import { prepareFieldsForTransformation } from '../case/utils'; const handshakeHandler = async ({ @@ -92,9 +94,10 @@ const pushToServiceHandler = async ({ mapping.get('comments')?.actionType !== 'nothing' ) { res.comments = []; + const commentsTransformed = transformComments(comments, ['informationAdded']); const fieldsKey = mapping.get('comments')?.target ?? 'comments'; - for (const currentComment of comments) { + for (const currentComment of commentsTransformed) { await externalService.updateIncident({ incidentId: res.id, incident: { @@ -118,7 +121,7 @@ export const transformFields = ({ params, fields, currentIncident, -}: TransformFieldsArgs): Record => { +}: TransformFieldsArgs): Record => { return fields.reduce((prev, cur) => { const transform = flow(...cur.pipes.map((p) => transformers[p])); return { @@ -126,20 +129,35 @@ export const transformFields = ({ [cur.key]: transform({ value: cur.value, date: params.updatedAt ?? params.createdAt, - user: - (params.updatedBy != null - ? params.updatedBy.fullName - ? params.updatedBy.fullName - : params.updatedBy.username - : params.createdBy.fullName - ? params.createdBy.fullName - : params.createdBy.username) ?? '', + user: getEntity(params), previousValue: currentIncident ? currentIncident[cur.key] : '', }).value, }; }, {}); }; +export const transformComments = (comments: Comment[], pipes: string[]): Comment[] => { + return comments.map((c) => ({ + ...c, + comment: flow(...pipes.map((p) => transformers[p]))({ + value: c.comment, + date: c.updatedAt ?? c.createdAt, + user: getEntity(c), + }).value, + })); +}; + +export const getEntity = (entity: EntityInformation): string => + (entity.updatedBy != null + ? entity.updatedBy.fullName + ? entity.updatedBy.fullName + : entity.updatedBy.username + : entity.createdBy != null + ? entity.createdBy.fullName + ? entity.createdBy.fullName + : entity.createdBy.username + : '') ?? ''; + export const api: ExternalServiceApi = { handshake: handshakeHandler, pushToService: pushToServiceHandler, diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts index 3addbe7c54da..41a577918b18 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts @@ -24,11 +24,11 @@ import { ExecutorSubActionPushParams, ServiceNowPublicConfigurationType, ServiceNowSecretConfigurationType, + PushToServiceResponse, } from './types'; // TODO: to remove, need to support Case import { buildMap, mapParams } from '../case/utils'; -import { PushToServiceResponse } from './case_types'; interface GetActionTypeParams { logger: Logger; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts index 5f22fcd4fdc8..55a14e4528ac 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts @@ -5,7 +5,7 @@ */ import { ExternalService, PushToServiceApiParams, ExecutorSubActionPushParams } from './types'; -import { MapRecord } from './case_types'; +import { MapRecord } from '../case/common_types'; const createMock = (): jest.Mocked => { const service = { diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts index 82afebaaee44..921de42adfca 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts @@ -5,7 +5,11 @@ */ import { schema } from '@kbn/config-schema'; -import { CommentSchema, EntityInformation, IncidentConfigurationSchema } from './case_shema'; +import { + CommentSchema, + EntityInformation, + IncidentConfigurationSchema, +} from '../case/common_schema'; export const ExternalIncidentServiceConfiguration = { apiUrl: schema.string(), diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/translations.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/translations.ts index 05c7d805a185..7cc97a241c4b 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/translations.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/translations.ts @@ -10,8 +10,8 @@ export const NAME = i18n.translate('xpack.actions.builtin.servicenowTitle', { defaultMessage: 'ServiceNow', }); -export const WHITE_LISTED_ERROR = (message: string) => - i18n.translate('xpack.actions.builtin.configuration.apiWhitelistError', { +export const ALLOWED_HOSTS_ERROR = (message: string) => + i18n.translate('xpack.actions.builtin.configuration.apiAllowedHostsError', { defaultMessage: 'error configuring connector action: {message}', values: { message, diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts index 0db9b6642ea5..e8fcfac45d78 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts @@ -16,8 +16,8 @@ import { ExecutorSubActionHandshakeParamsSchema, } from './schema'; import { ActionsConfigurationUtilities } from '../../actions_config'; -import { IncidentConfigurationSchema } from './case_shema'; -import { PushToServiceResponse } from './case_types'; +import { ExternalServiceCommentResponse } from '../case/common_types'; +import { IncidentConfigurationSchema } from '../case/common_schema'; import { Logger } from '../../../../../../src/core/server'; export type ServiceNowPublicConfigurationType = TypeOf< @@ -52,6 +52,9 @@ export interface ExternalServiceIncidentResponse { url: string; pushedDate: string; } +export interface PushToServiceResponse extends ExternalServiceIncidentResponse { + comments?: ExternalServiceCommentResponse[]; +} export type ExternalServiceParams = Record; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/validators.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/validators.ts index 6eec3b8d63b8..87bbfd9c7ea9 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/validators.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/validators.ts @@ -27,8 +27,8 @@ export const validateCommonConfig = ( try { configurationUtilities.ensureUriAllowed(configObject.apiUrl); - } catch (allowListError) { - return i18n.WHITE_LISTED_ERROR(allowListError.message); + } catch (allowedListError) { + return i18n.ALLOWED_HOSTS_ERROR(allowedListError.message); } }; diff --git a/x-pack/plugins/alerts/README.md b/x-pack/plugins/alerts/README.md index aab05cb0a7cf..6307e463af85 100644 --- a/x-pack/plugins/alerts/README.md +++ b/x-pack/plugins/alerts/README.md @@ -26,7 +26,7 @@ Table of Contents - [`GET /api/alerts/_find`: Find alerts](#get-apialertfind-find-alerts) - [`GET /api/alerts/alert/{id}`: Get alert](#get-apialertid-get-alert) - [`GET /api/alerts/alert/{id}/state`: Get alert state](#get-apialertidstate-get-alert-state) - - [`GET /api/alerts/alert/{id}/status`: Get alert status](#get-apialertidstate-get-alert-status) + - [`GET /api/alerts/alert/{id}/_instance_summary`: Get alert instance summary](#get-apialertidstate-get-alert-instance-summary) - [`GET /api/alerts/list_alert_types`: List alert types](#get-apialerttypes-list-alert-types) - [`PUT /api/alerts/alert/{id}`: Update alert](#put-apialertid-update-alert) - [`POST /api/alerts/alert/{id}/_enable`: Enable an alert](#post-apialertidenable-enable-an-alert) @@ -505,7 +505,7 @@ Params: |---|---|---| |id|The id of the alert whose state you're trying to get.|string| -### `GET /api/alerts/alert/{id}/status`: Get alert status +### `GET /api/alerts/alert/{id}/_instance_summary`: Get alert instance summary Similar to the `GET state` call, but collects additional information from the event log. @@ -514,7 +514,7 @@ Params: |Property|Description|Type| |---|---|---| -|id|The id of the alert whose status you're trying to get.|string| +|id|The id of the alert whose instance summary you're trying to get.|string| Query: diff --git a/x-pack/plugins/alerts/common/alert_status.ts b/x-pack/plugins/alerts/common/alert_instance_summary.ts similarity index 95% rename from x-pack/plugins/alerts/common/alert_status.ts rename to x-pack/plugins/alerts/common/alert_instance_summary.ts index 517db6d6cb24..333db3ccda96 100644 --- a/x-pack/plugins/alerts/common/alert_status.ts +++ b/x-pack/plugins/alerts/common/alert_instance_summary.ts @@ -7,7 +7,7 @@ type AlertStatusValues = 'OK' | 'Active' | 'Error'; type AlertInstanceStatusValues = 'OK' | 'Active'; -export interface AlertStatus { +export interface AlertInstanceSummary { id: string; name: string; tags: string[]; diff --git a/x-pack/plugins/alerts/common/index.ts b/x-pack/plugins/alerts/common/index.ts index 0922e164a3aa..ab71f77a049f 100644 --- a/x-pack/plugins/alerts/common/index.ts +++ b/x-pack/plugins/alerts/common/index.ts @@ -9,7 +9,7 @@ export * from './alert_type'; export * from './alert_instance'; export * from './alert_task_instance'; export * from './alert_navigation'; -export * from './alert_status'; +export * from './alert_instance_summary'; export interface ActionGroup { id: string; diff --git a/x-pack/plugins/alerts/server/alerts_client.mock.ts b/x-pack/plugins/alerts/server/alerts_client.mock.ts index b61139ae72c9..b28e9f805f72 100644 --- a/x-pack/plugins/alerts/server/alerts_client.mock.ts +++ b/x-pack/plugins/alerts/server/alerts_client.mock.ts @@ -25,7 +25,7 @@ const createAlertsClientMock = () => { muteInstance: jest.fn(), unmuteInstance: jest.fn(), listAlertTypes: jest.fn(), - getAlertStatus: jest.fn(), + getAlertInstanceSummary: jest.fn(), }; return mocked; }; diff --git a/x-pack/plugins/alerts/server/alerts_client.test.ts b/x-pack/plugins/alerts/server/alerts_client.test.ts index f4aef62657ab..801c2c877536 100644 --- a/x-pack/plugins/alerts/server/alerts_client.test.ts +++ b/x-pack/plugins/alerts/server/alerts_client.test.ts @@ -20,7 +20,7 @@ import { ActionsAuthorization } from '../../actions/server'; import { eventLogClientMock } from '../../event_log/server/mocks'; import { QueryEventsBySavedObjectResult } from '../../event_log/server'; import { SavedObject } from 'kibana/server'; -import { EventsFactory } from './lib/alert_status_from_event_log.test'; +import { EventsFactory } from './lib/alert_instance_summary_from_event_log.test'; const taskManager = taskManagerMock.start(); const alertTypeRegistry = alertTypeRegistryMock.create(); @@ -2382,16 +2382,16 @@ describe('getAlertState()', () => { }); }); -const AlertStatusFindEventsResult: QueryEventsBySavedObjectResult = { +const AlertInstanceSummaryFindEventsResult: QueryEventsBySavedObjectResult = { page: 1, per_page: 10000, total: 0, data: [], }; -const AlertStatusIntervalSeconds = 1; +const AlertInstanceSummaryIntervalSeconds = 1; -const BaseAlertStatusSavedObject: SavedObject = { +const BaseAlertInstanceSummarySavedObject: SavedObject = { id: '1', type: 'alert', attributes: { @@ -2400,7 +2400,7 @@ const BaseAlertStatusSavedObject: SavedObject = { tags: ['tag-1', 'tag-2'], alertTypeId: '123', consumer: 'alert-consumer', - schedule: { interval: `${AlertStatusIntervalSeconds}s` }, + schedule: { interval: `${AlertInstanceSummaryIntervalSeconds}s` }, actions: [], params: {}, createdBy: null, @@ -2415,14 +2415,16 @@ const BaseAlertStatusSavedObject: SavedObject = { references: [], }; -function getAlertStatusSavedObject(attributes: Partial = {}): SavedObject { +function getAlertInstanceSummarySavedObject( + attributes: Partial = {} +): SavedObject { return { - ...BaseAlertStatusSavedObject, - attributes: { ...BaseAlertStatusSavedObject.attributes, ...attributes }, + ...BaseAlertInstanceSummarySavedObject, + attributes: { ...BaseAlertInstanceSummarySavedObject.attributes, ...attributes }, }; } -describe('getAlertStatus()', () => { +describe('getAlertInstanceSummary()', () => { let alertsClient: AlertsClient; beforeEach(() => { @@ -2430,7 +2432,9 @@ describe('getAlertStatus()', () => { }); test('runs as expected with some event log data', async () => { - const alertSO = getAlertStatusSavedObject({ mutedInstanceIds: ['instance-muted-no-activity'] }); + const alertSO = getAlertInstanceSummarySavedObject({ + mutedInstanceIds: ['instance-muted-no-activity'], + }); unsecuredSavedObjectsClient.get.mockResolvedValueOnce(alertSO); const eventsFactory = new EventsFactory(mockedDateString); @@ -2446,7 +2450,7 @@ describe('getAlertStatus()', () => { .addActiveInstance('instance-currently-active') .getEvents(); const eventsResult = { - ...AlertStatusFindEventsResult, + ...AlertInstanceSummaryFindEventsResult, total: events.length, data: events, }; @@ -2454,7 +2458,7 @@ describe('getAlertStatus()', () => { const dateStart = new Date(Date.now() - 60 * 1000).toISOString(); - const result = await alertsClient.getAlertStatus({ id: '1', dateStart }); + const result = await alertsClient.getAlertInstanceSummary({ id: '1', dateStart }); expect(result).toMatchInlineSnapshot(` Object { "alertTypeId": "123", @@ -2494,16 +2498,18 @@ describe('getAlertStatus()', () => { `); }); - // Further tests don't check the result of `getAlertStatus()`, as the result - // is just the result from the `alertStatusFromEventLog()`, which itself + // Further tests don't check the result of `getAlertInstanceSummary()`, as the result + // is just the result from the `alertInstanceSummaryFromEventLog()`, which itself // has a complete set of tests. These tests just make sure the data gets - // sent into `getAlertStatus()` as appropriate. + // sent into `getAlertInstanceSummary()` as appropriate. test('calls saved objects and event log client with default params', async () => { - unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertStatusSavedObject()); - eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(AlertStatusFindEventsResult); + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertInstanceSummarySavedObject()); + eventLogClient.findEventsBySavedObject.mockResolvedValueOnce( + AlertInstanceSummaryFindEventsResult + ); - await alertsClient.getAlertStatus({ id: '1' }); + await alertsClient.getAlertInstanceSummary({ id: '1' }); expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); expect(eventLogClient.findEventsBySavedObject).toHaveBeenCalledTimes(1); @@ -2526,17 +2532,21 @@ describe('getAlertStatus()', () => { const startMillis = Date.parse(start!); const endMillis = Date.parse(end!); - const expectedDuration = 60 * AlertStatusIntervalSeconds * 1000; + const expectedDuration = 60 * AlertInstanceSummaryIntervalSeconds * 1000; expect(endMillis - startMillis).toBeGreaterThan(expectedDuration - 2); expect(endMillis - startMillis).toBeLessThan(expectedDuration + 2); }); test('calls event log client with start date', async () => { - unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertStatusSavedObject()); - eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(AlertStatusFindEventsResult); + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertInstanceSummarySavedObject()); + eventLogClient.findEventsBySavedObject.mockResolvedValueOnce( + AlertInstanceSummaryFindEventsResult + ); - const dateStart = new Date(Date.now() - 60 * AlertStatusIntervalSeconds * 1000).toISOString(); - await alertsClient.getAlertStatus({ id: '1', dateStart }); + const dateStart = new Date( + Date.now() - 60 * AlertInstanceSummaryIntervalSeconds * 1000 + ).toISOString(); + await alertsClient.getAlertInstanceSummary({ id: '1', dateStart }); expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); expect(eventLogClient.findEventsBySavedObject).toHaveBeenCalledTimes(1); @@ -2551,11 +2561,13 @@ describe('getAlertStatus()', () => { }); test('calls event log client with relative start date', async () => { - unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertStatusSavedObject()); - eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(AlertStatusFindEventsResult); + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertInstanceSummarySavedObject()); + eventLogClient.findEventsBySavedObject.mockResolvedValueOnce( + AlertInstanceSummaryFindEventsResult + ); const dateStart = '2m'; - await alertsClient.getAlertStatus({ id: '1', dateStart }); + await alertsClient.getAlertInstanceSummary({ id: '1', dateStart }); expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); expect(eventLogClient.findEventsBySavedObject).toHaveBeenCalledTimes(1); @@ -2570,28 +2582,36 @@ describe('getAlertStatus()', () => { }); test('invalid start date throws an error', async () => { - unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertStatusSavedObject()); - eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(AlertStatusFindEventsResult); + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertInstanceSummarySavedObject()); + eventLogClient.findEventsBySavedObject.mockResolvedValueOnce( + AlertInstanceSummaryFindEventsResult + ); const dateStart = 'ain"t no way this will get parsed as a date'; - expect(alertsClient.getAlertStatus({ id: '1', dateStart })).rejects.toMatchInlineSnapshot( + expect( + alertsClient.getAlertInstanceSummary({ id: '1', dateStart }) + ).rejects.toMatchInlineSnapshot( `[Error: Invalid date for parameter dateStart: "ain"t no way this will get parsed as a date"]` ); }); test('saved object get throws an error', async () => { unsecuredSavedObjectsClient.get.mockRejectedValueOnce(new Error('OMG!')); - eventLogClient.findEventsBySavedObject.mockResolvedValueOnce(AlertStatusFindEventsResult); + eventLogClient.findEventsBySavedObject.mockResolvedValueOnce( + AlertInstanceSummaryFindEventsResult + ); - expect(alertsClient.getAlertStatus({ id: '1' })).rejects.toMatchInlineSnapshot(`[Error: OMG!]`); + expect(alertsClient.getAlertInstanceSummary({ id: '1' })).rejects.toMatchInlineSnapshot( + `[Error: OMG!]` + ); }); test('findEvents throws an error', async () => { - unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertStatusSavedObject()); + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(getAlertInstanceSummarySavedObject()); eventLogClient.findEventsBySavedObject.mockRejectedValueOnce(new Error('OMG 2!')); // error eaten but logged - await alertsClient.getAlertStatus({ id: '1' }); + await alertsClient.getAlertInstanceSummary({ id: '1' }); }); }); diff --git a/x-pack/plugins/alerts/server/alerts_client.ts b/x-pack/plugins/alerts/server/alerts_client.ts index 74aef644d58c..0703a1e13937 100644 --- a/x-pack/plugins/alerts/server/alerts_client.ts +++ b/x-pack/plugins/alerts/server/alerts_client.ts @@ -24,7 +24,7 @@ import { IntervalSchedule, SanitizedAlert, AlertTaskState, - AlertStatus, + AlertInstanceSummary, } from './types'; import { validateAlertTypeParams } from './lib'; import { @@ -44,7 +44,7 @@ import { } from './authorization/alerts_authorization'; import { IEventLogClient } from '../../../plugins/event_log/server'; import { parseIsoOrRelativeDate } from './lib/iso_or_relative_date'; -import { alertStatusFromEventLog } from './lib/alert_status_from_event_log'; +import { alertInstanceSummaryFromEventLog } from './lib/alert_instance_summary_from_event_log'; import { IEvent } from '../../event_log/server'; import { parseDuration } from '../common/parse_duration'; @@ -139,7 +139,7 @@ interface UpdateOptions { }; } -interface GetAlertStatusParams { +interface GetAlertInstanceSummaryParams { id: string; dateStart?: string; } @@ -284,16 +284,19 @@ export class AlertsClient { } } - public async getAlertStatus({ id, dateStart }: GetAlertStatusParams): Promise { - this.logger.debug(`getAlertStatus(): getting alert ${id}`); + public async getAlertInstanceSummary({ + id, + dateStart, + }: GetAlertInstanceSummaryParams): Promise { + this.logger.debug(`getAlertInstanceSummary(): getting alert ${id}`); const alert = await this.get({ id }); await this.authorization.ensureAuthorized( alert.alertTypeId, alert.consumer, - ReadOperations.GetAlertStatus + ReadOperations.GetAlertInstanceSummary ); - // default duration of status is 60 * alert interval + // default duration of instance summary is 60 * alert interval const dateNow = new Date(); const durationMillis = parseDuration(alert.schedule.interval) * 60; const defaultDateStart = new Date(dateNow.valueOf() - durationMillis); @@ -301,7 +304,7 @@ export class AlertsClient { const eventLogClient = await this.getEventLogClient(); - this.logger.debug(`getAlertStatus(): search the event log for alert ${id}`); + this.logger.debug(`getAlertInstanceSummary(): search the event log for alert ${id}`); let events: IEvent[]; try { const queryResults = await eventLogClient.findEventsBySavedObject('alert', id, { @@ -314,12 +317,12 @@ export class AlertsClient { events = queryResults.data; } catch (err) { this.logger.debug( - `alertsClient.getAlertStatus(): error searching event log for alert ${id}: ${err.message}` + `alertsClient.getAlertInstanceSummary(): error searching event log for alert ${id}: ${err.message}` ); events = []; } - return alertStatusFromEventLog({ + return alertInstanceSummaryFromEventLog({ alert, events, dateStart: parsedDateStart.toISOString(), @@ -952,7 +955,7 @@ function parseDate(dateString: string | undefined, propertyName: string, default const parsedDate = parseIsoOrRelativeDate(dateString); if (parsedDate === undefined) { throw Boom.badRequest( - i18n.translate('xpack.alerts.alertsClient.getAlertStatus.invalidDate', { + i18n.translate('xpack.alerts.alertsClient.invalidDate', { defaultMessage: 'Invalid date for parameter {field}: "{dateValue}"', values: { field: propertyName, diff --git a/x-pack/plugins/alerts/server/authorization/alerts_authorization.ts b/x-pack/plugins/alerts/server/authorization/alerts_authorization.ts index b2a214eae931..b362a50c9f10 100644 --- a/x-pack/plugins/alerts/server/authorization/alerts_authorization.ts +++ b/x-pack/plugins/alerts/server/authorization/alerts_authorization.ts @@ -18,7 +18,7 @@ import { Space } from '../../../spaces/server'; export enum ReadOperations { Get = 'get', GetAlertState = 'getAlertState', - GetAlertStatus = 'getAlertStatus', + GetAlertInstanceSummary = 'getAlertInstanceSummary', Find = 'find', } diff --git a/x-pack/plugins/alerts/server/lib/alert_status_from_event_log.test.ts b/x-pack/plugins/alerts/server/lib/alert_instance_summary_from_event_log.test.ts similarity index 83% rename from x-pack/plugins/alerts/server/lib/alert_status_from_event_log.test.ts rename to x-pack/plugins/alerts/server/lib/alert_instance_summary_from_event_log.test.ts index 15570d3032f2..b5936cf3577b 100644 --- a/x-pack/plugins/alerts/server/lib/alert_status_from_event_log.test.ts +++ b/x-pack/plugins/alerts/server/lib/alert_instance_summary_from_event_log.test.ts @@ -4,22 +4,27 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SanitizedAlert, AlertStatus } from '../types'; +import { SanitizedAlert, AlertInstanceSummary } from '../types'; import { IValidatedEvent } from '../../../event_log/server'; import { EVENT_LOG_ACTIONS, EVENT_LOG_PROVIDER } from '../plugin'; -import { alertStatusFromEventLog } from './alert_status_from_event_log'; +import { alertInstanceSummaryFromEventLog } from './alert_instance_summary_from_event_log'; const ONE_HOUR_IN_MILLIS = 60 * 60 * 1000; const dateStart = '2020-06-18T00:00:00.000Z'; const dateEnd = dateString(dateStart, ONE_HOUR_IN_MILLIS); -describe('alertStatusFromEventLog', () => { +describe('alertInstanceSummaryFromEventLog', () => { test('no events and muted ids', async () => { const alert = createAlert({}); const events: IValidatedEvent[] = []; - const status: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + const summary: AlertInstanceSummary = alertInstanceSummaryFromEventLog({ + alert, + events, + dateStart, + dateEnd, + }); - expect(status).toMatchInlineSnapshot(` + expect(summary).toMatchInlineSnapshot(` Object { "alertTypeId": "123", "consumer": "alert-consumer", @@ -52,14 +57,14 @@ describe('alertStatusFromEventLog', () => { muteAll: true, }); const events: IValidatedEvent[] = []; - const status: AlertStatus = alertStatusFromEventLog({ + const summary: AlertInstanceSummary = alertInstanceSummaryFromEventLog({ alert, events, dateStart: dateString(dateEnd, ONE_HOUR_IN_MILLIS), dateEnd: dateString(dateEnd, ONE_HOUR_IN_MILLIS * 2), }); - expect(status).toMatchInlineSnapshot(` + expect(summary).toMatchInlineSnapshot(` Object { "alertTypeId": "456", "consumer": "alert-consumer-2", @@ -87,9 +92,14 @@ describe('alertStatusFromEventLog', () => { mutedInstanceIds: ['instance-1', 'instance-2'], }); const events: IValidatedEvent[] = []; - const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + const summary: AlertInstanceSummary = alertInstanceSummaryFromEventLog({ + alert, + events, + dateStart, + dateEnd, + }); - const { lastRun, status, instances } = alertStatus; + const { lastRun, status, instances } = summary; expect({ lastRun, status, instances }).toMatchInlineSnapshot(` Object { "instances": Object { @@ -115,9 +125,14 @@ describe('alertStatusFromEventLog', () => { const eventsFactory = new EventsFactory(); const events = eventsFactory.addExecute().advanceTime(10000).addExecute().getEvents(); - const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + const summary: AlertInstanceSummary = alertInstanceSummaryFromEventLog({ + alert, + events, + dateStart, + dateEnd, + }); - const { lastRun, status, instances } = alertStatus; + const { lastRun, status, instances } = summary; expect({ lastRun, status, instances }).toMatchInlineSnapshot(` Object { "instances": Object {}, @@ -136,9 +151,14 @@ describe('alertStatusFromEventLog', () => { .addExecute('rut roh!') .getEvents(); - const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + const summary: AlertInstanceSummary = alertInstanceSummaryFromEventLog({ + alert, + events, + dateStart, + dateEnd, + }); - const { lastRun, status, errorMessages, instances } = alertStatus; + const { lastRun, status, errorMessages, instances } = summary; expect({ lastRun, status, errorMessages, instances }).toMatchInlineSnapshot(` Object { "errorMessages": Array [ @@ -170,9 +190,14 @@ describe('alertStatusFromEventLog', () => { .addResolvedInstance('instance-1') .getEvents(); - const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + const summary: AlertInstanceSummary = alertInstanceSummaryFromEventLog({ + alert, + events, + dateStart, + dateEnd, + }); - const { lastRun, status, instances } = alertStatus; + const { lastRun, status, instances } = summary; expect({ lastRun, status, instances }).toMatchInlineSnapshot(` Object { "instances": Object { @@ -199,9 +224,14 @@ describe('alertStatusFromEventLog', () => { .addResolvedInstance('instance-1') .getEvents(); - const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + const summary: AlertInstanceSummary = alertInstanceSummaryFromEventLog({ + alert, + events, + dateStart, + dateEnd, + }); - const { lastRun, status, instances } = alertStatus; + const { lastRun, status, instances } = summary; expect({ lastRun, status, instances }).toMatchInlineSnapshot(` Object { "instances": Object { @@ -229,9 +259,14 @@ describe('alertStatusFromEventLog', () => { .addActiveInstance('instance-1') .getEvents(); - const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + const summary: AlertInstanceSummary = alertInstanceSummaryFromEventLog({ + alert, + events, + dateStart, + dateEnd, + }); - const { lastRun, status, instances } = alertStatus; + const { lastRun, status, instances } = summary; expect({ lastRun, status, instances }).toMatchInlineSnapshot(` Object { "instances": Object { @@ -258,9 +293,14 @@ describe('alertStatusFromEventLog', () => { .addActiveInstance('instance-1') .getEvents(); - const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + const summary: AlertInstanceSummary = alertInstanceSummaryFromEventLog({ + alert, + events, + dateStart, + dateEnd, + }); - const { lastRun, status, instances } = alertStatus; + const { lastRun, status, instances } = summary; expect({ lastRun, status, instances }).toMatchInlineSnapshot(` Object { "instances": Object { @@ -291,9 +331,14 @@ describe('alertStatusFromEventLog', () => { .addResolvedInstance('instance-2') .getEvents(); - const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + const summary: AlertInstanceSummary = alertInstanceSummaryFromEventLog({ + alert, + events, + dateStart, + dateEnd, + }); - const { lastRun, status, instances } = alertStatus; + const { lastRun, status, instances } = summary; expect({ lastRun, status, instances }).toMatchInlineSnapshot(` Object { "instances": Object { @@ -335,9 +380,14 @@ describe('alertStatusFromEventLog', () => { .addActiveInstance('instance-1') .getEvents(); - const alertStatus: AlertStatus = alertStatusFromEventLog({ alert, events, dateStart, dateEnd }); + const summary: AlertInstanceSummary = alertInstanceSummaryFromEventLog({ + alert, + events, + dateStart, + dateEnd, + }); - const { lastRun, status, instances } = alertStatus; + const { lastRun, status, instances } = summary; expect({ lastRun, status, instances }).toMatchInlineSnapshot(` Object { "instances": Object { diff --git a/x-pack/plugins/alerts/server/lib/alert_status_from_event_log.ts b/x-pack/plugins/alerts/server/lib/alert_instance_summary_from_event_log.ts similarity index 79% rename from x-pack/plugins/alerts/server/lib/alert_status_from_event_log.ts rename to x-pack/plugins/alerts/server/lib/alert_instance_summary_from_event_log.ts index 606bd44c6990..9a5e870c8199 100644 --- a/x-pack/plugins/alerts/server/lib/alert_status_from_event_log.ts +++ b/x-pack/plugins/alerts/server/lib/alert_instance_summary_from_event_log.ts @@ -4,21 +4,23 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SanitizedAlert, AlertStatus, AlertInstanceStatus } from '../types'; +import { SanitizedAlert, AlertInstanceSummary, AlertInstanceStatus } from '../types'; import { IEvent } from '../../../event_log/server'; import { EVENT_LOG_ACTIONS, EVENT_LOG_PROVIDER } from '../plugin'; -export interface AlertStatusFromEventLogParams { +export interface AlertInstanceSummaryFromEventLogParams { alert: SanitizedAlert; events: IEvent[]; dateStart: string; dateEnd: string; } -export function alertStatusFromEventLog(params: AlertStatusFromEventLogParams): AlertStatus { +export function alertInstanceSummaryFromEventLog( + params: AlertInstanceSummaryFromEventLogParams +): AlertInstanceSummary { // initialize the result const { alert, events, dateStart, dateEnd } = params; - const alertStatus: AlertStatus = { + const alertInstanceSummary: AlertInstanceSummary = { id: alert.id, name: alert.name, tags: alert.tags, @@ -50,17 +52,17 @@ export function alertStatusFromEventLog(params: AlertStatusFromEventLogParams): if (action === undefined) continue; if (action === EVENT_LOG_ACTIONS.execute) { - alertStatus.lastRun = timeStamp; + alertInstanceSummary.lastRun = timeStamp; const errorMessage = event?.error?.message; if (errorMessage !== undefined) { - alertStatus.status = 'Error'; - alertStatus.errorMessages.push({ + alertInstanceSummary.status = 'Error'; + alertInstanceSummary.errorMessages.push({ date: timeStamp, message: errorMessage, }); } else { - alertStatus.status = 'OK'; + alertInstanceSummary.status = 'OK'; } continue; @@ -91,19 +93,19 @@ export function alertStatusFromEventLog(params: AlertStatusFromEventLogParams): // convert the instances map to object form const instanceIds = Array.from(instances.keys()).sort(); for (const instanceId of instanceIds) { - alertStatus.instances[instanceId] = instances.get(instanceId)!; + alertInstanceSummary.instances[instanceId] = instances.get(instanceId)!; } // set the overall alert status to Active if appropriate - if (alertStatus.status !== 'Error') { + if (alertInstanceSummary.status !== 'Error') { if (Array.from(instances.values()).some((instance) => instance.status === 'Active')) { - alertStatus.status = 'Active'; + alertInstanceSummary.status = 'Active'; } } - alertStatus.errorMessages.sort((a, b) => a.date.localeCompare(b.date)); + alertInstanceSummary.errorMessages.sort((a, b) => a.date.localeCompare(b.date)); - return alertStatus; + return alertInstanceSummary; } // return an instance status object, creating and adding to the map if needed diff --git a/x-pack/plugins/alerts/server/plugin.ts b/x-pack/plugins/alerts/server/plugin.ts index b16ded9fb5c9..4f9b1f7c22e6 100644 --- a/x-pack/plugins/alerts/server/plugin.ts +++ b/x-pack/plugins/alerts/server/plugin.ts @@ -38,7 +38,7 @@ import { findAlertRoute, getAlertRoute, getAlertStateRoute, - getAlertStatusRoute, + getAlertInstanceSummaryRoute, listAlertTypesRoute, updateAlertRoute, enableAlertRoute, @@ -193,7 +193,7 @@ export class AlertingPlugin { findAlertRoute(router, this.licenseState); getAlertRoute(router, this.licenseState); getAlertStateRoute(router, this.licenseState); - getAlertStatusRoute(router, this.licenseState); + getAlertInstanceSummaryRoute(router, this.licenseState); listAlertTypesRoute(router, this.licenseState); updateAlertRoute(router, this.licenseState); enableAlertRoute(router, this.licenseState); diff --git a/x-pack/plugins/alerts/server/routes/get_alert_status.test.ts b/x-pack/plugins/alerts/server/routes/get_alert_instance_summary.test.ts similarity index 75% rename from x-pack/plugins/alerts/server/routes/get_alert_status.test.ts rename to x-pack/plugins/alerts/server/routes/get_alert_instance_summary.test.ts index 1b4cb1941018..8957a3d7c091 100644 --- a/x-pack/plugins/alerts/server/routes/get_alert_status.test.ts +++ b/x-pack/plugins/alerts/server/routes/get_alert_instance_summary.test.ts @@ -4,13 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { getAlertStatusRoute } from './get_alert_status'; +import { getAlertInstanceSummaryRoute } from './get_alert_instance_summary'; import { httpServiceMock } from 'src/core/server/mocks'; import { mockLicenseState } from '../lib/license_state.mock'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { SavedObjectsErrorHelpers } from 'src/core/server'; import { alertsClientMock } from '../alerts_client.mock'; -import { AlertStatus } from '../types'; +import { AlertInstanceSummary } from '../types'; const alertsClient = alertsClientMock.create(); jest.mock('../lib/license_api_access.ts', () => ({ @@ -21,9 +21,9 @@ beforeEach(() => { jest.resetAllMocks(); }); -describe('getAlertStatusRoute', () => { +describe('getAlertInstanceSummaryRoute', () => { const dateString = new Date().toISOString(); - const mockedAlertStatus: AlertStatus = { + const mockedAlertInstanceSummary: AlertInstanceSummary = { id: '', name: '', tags: [], @@ -39,17 +39,17 @@ describe('getAlertStatusRoute', () => { instances: {}, }; - it('gets alert status', async () => { + it('gets alert instance summary', async () => { const licenseState = mockLicenseState(); const router = httpServiceMock.createRouter(); - getAlertStatusRoute(router, licenseState); + getAlertInstanceSummaryRoute(router, licenseState); const [config, handler] = router.get.mock.calls[0]; - expect(config.path).toMatchInlineSnapshot(`"/api/alerts/alert/{id}/status"`); + expect(config.path).toMatchInlineSnapshot(`"/api/alerts/alert/{id}/_instance_summary"`); - alertsClient.getAlertStatus.mockResolvedValueOnce(mockedAlertStatus); + alertsClient.getAlertInstanceSummary.mockResolvedValueOnce(mockedAlertInstanceSummary); const [context, req, res] = mockHandlerArguments( { alertsClient }, @@ -64,8 +64,8 @@ describe('getAlertStatusRoute', () => { await handler(context, req, res); - expect(alertsClient.getAlertStatus).toHaveBeenCalledTimes(1); - expect(alertsClient.getAlertStatus.mock.calls[0]).toMatchInlineSnapshot(` + expect(alertsClient.getAlertInstanceSummary).toHaveBeenCalledTimes(1); + expect(alertsClient.getAlertInstanceSummary.mock.calls[0]).toMatchInlineSnapshot(` Array [ Object { "dateStart": undefined, @@ -81,11 +81,11 @@ describe('getAlertStatusRoute', () => { const licenseState = mockLicenseState(); const router = httpServiceMock.createRouter(); - getAlertStatusRoute(router, licenseState); + getAlertInstanceSummaryRoute(router, licenseState); const [, handler] = router.get.mock.calls[0]; - alertsClient.getAlertStatus = jest + alertsClient.getAlertInstanceSummary = jest .fn() .mockResolvedValueOnce(SavedObjectsErrorHelpers.createGenericNotFoundError('alert', '1')); diff --git a/x-pack/plugins/alerts/server/routes/get_alert_status.ts b/x-pack/plugins/alerts/server/routes/get_alert_instance_summary.ts similarity index 83% rename from x-pack/plugins/alerts/server/routes/get_alert_status.ts rename to x-pack/plugins/alerts/server/routes/get_alert_instance_summary.ts index eab18c50189f..11a10c2967a5 100644 --- a/x-pack/plugins/alerts/server/routes/get_alert_status.ts +++ b/x-pack/plugins/alerts/server/routes/get_alert_instance_summary.ts @@ -24,10 +24,10 @@ const querySchema = schema.object({ dateStart: schema.maybe(schema.string()), }); -export const getAlertStatusRoute = (router: IRouter, licenseState: LicenseState) => { +export const getAlertInstanceSummaryRoute = (router: IRouter, licenseState: LicenseState) => { router.get( { - path: `${BASE_ALERT_API_PATH}/alert/{id}/status`, + path: `${BASE_ALERT_API_PATH}/alert/{id}/_instance_summary`, validate: { params: paramSchema, query: querySchema, @@ -45,8 +45,8 @@ export const getAlertStatusRoute = (router: IRouter, licenseState: LicenseState) const alertsClient = context.alerting.getAlertsClient(); const { id } = req.params; const { dateStart } = req.query; - const status = await alertsClient.getAlertStatus({ id, dateStart }); - return res.ok({ body: status }); + const summary = await alertsClient.getAlertInstanceSummary({ id, dateStart }); + return res.ok({ body: summary }); }) ); }; diff --git a/x-pack/plugins/alerts/server/routes/index.ts b/x-pack/plugins/alerts/server/routes/index.ts index 4c6b1eb8e9b5..aed66e82d11f 100644 --- a/x-pack/plugins/alerts/server/routes/index.ts +++ b/x-pack/plugins/alerts/server/routes/index.ts @@ -9,7 +9,7 @@ export { deleteAlertRoute } from './delete'; export { findAlertRoute } from './find'; export { getAlertRoute } from './get'; export { getAlertStateRoute } from './get_alert_state'; -export { getAlertStatusRoute } from './get_alert_status'; +export { getAlertInstanceSummaryRoute } from './get_alert_instance_summary'; export { listAlertTypesRoute } from './list_alert_types'; export { updateAlertRoute } from './update'; export { enableAlertRoute } from './enable'; diff --git a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap index 6238fbfdaa1a..8218eefe738f 100644 --- a/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap +++ b/x-pack/plugins/apm/common/__snapshots__/elasticsearch_fieldnames.test.ts.snap @@ -14,6 +14,8 @@ exports[`Error CLOUD_PROVIDER 1`] = `"gcp"`; exports[`Error CLOUD_REGION 1`] = `"europe-west1"`; +exports[`Error CLS_FIELD 1`] = `undefined`; + exports[`Error CONTAINER_ID 1`] = `undefined`; exports[`Error DESTINATION_ADDRESS 1`] = `undefined`; @@ -34,6 +36,10 @@ exports[`Error ERROR_LOG_MESSAGE 1`] = `undefined`; exports[`Error ERROR_PAGE_URL 1`] = `undefined`; +exports[`Error FCP_FIELD 1`] = `undefined`; + +exports[`Error FID_FIELD 1`] = `undefined`; + exports[`Error EVENT_OUTCOME 1`] = `undefined`; exports[`Error HOST_NAME 1`] = `"my hostname"`; @@ -44,6 +50,8 @@ exports[`Error HTTP_RESPONSE_STATUS_CODE 1`] = `undefined`; exports[`Error LABEL_NAME 1`] = `undefined`; +exports[`Error LCP_FIELD 1`] = `undefined`; + exports[`Error METRIC_JAVA_GC_COUNT 1`] = `undefined`; exports[`Error METRIC_JAVA_GC_TIME 1`] = `undefined`; @@ -118,6 +126,8 @@ exports[`Error SPAN_SUBTYPE 1`] = `undefined`; exports[`Error SPAN_TYPE 1`] = `undefined`; +exports[`Error TBT_FIELD 1`] = `undefined`; + exports[`Error TRACE_ID 1`] = `"trace id"`; exports[`Error TRANSACTION_BREAKDOWN_COUNT 1`] = `undefined`; @@ -168,6 +178,8 @@ exports[`Span CLOUD_PROVIDER 1`] = `"gcp"`; exports[`Span CLOUD_REGION 1`] = `"europe-west1"`; +exports[`Span CLS_FIELD 1`] = `undefined`; + exports[`Span CONTAINER_ID 1`] = `undefined`; exports[`Span DESTINATION_ADDRESS 1`] = `undefined`; @@ -188,6 +200,10 @@ exports[`Span ERROR_LOG_MESSAGE 1`] = `undefined`; exports[`Span ERROR_PAGE_URL 1`] = `undefined`; +exports[`Span FCP_FIELD 1`] = `undefined`; + +exports[`Span FID_FIELD 1`] = `undefined`; + exports[`Span EVENT_OUTCOME 1`] = `undefined`; exports[`Span HOST_NAME 1`] = `undefined`; @@ -198,6 +214,8 @@ exports[`Span HTTP_RESPONSE_STATUS_CODE 1`] = `undefined`; exports[`Span LABEL_NAME 1`] = `undefined`; +exports[`Span LCP_FIELD 1`] = `undefined`; + exports[`Span METRIC_JAVA_GC_COUNT 1`] = `undefined`; exports[`Span METRIC_JAVA_GC_TIME 1`] = `undefined`; @@ -272,6 +290,8 @@ exports[`Span SPAN_SUBTYPE 1`] = `"my subtype"`; exports[`Span SPAN_TYPE 1`] = `"span type"`; +exports[`Span TBT_FIELD 1`] = `undefined`; + exports[`Span TRACE_ID 1`] = `"trace id"`; exports[`Span TRANSACTION_BREAKDOWN_COUNT 1`] = `undefined`; @@ -322,6 +342,8 @@ exports[`Transaction CLOUD_PROVIDER 1`] = `"gcp"`; exports[`Transaction CLOUD_REGION 1`] = `"europe-west1"`; +exports[`Transaction CLS_FIELD 1`] = `undefined`; + exports[`Transaction CONTAINER_ID 1`] = `"container1234567890abcdef"`; exports[`Transaction DESTINATION_ADDRESS 1`] = `undefined`; @@ -342,6 +364,10 @@ exports[`Transaction ERROR_LOG_MESSAGE 1`] = `undefined`; exports[`Transaction ERROR_PAGE_URL 1`] = `undefined`; +exports[`Transaction FCP_FIELD 1`] = `undefined`; + +exports[`Transaction FID_FIELD 1`] = `undefined`; + exports[`Transaction EVENT_OUTCOME 1`] = `undefined`; exports[`Transaction HOST_NAME 1`] = `"my hostname"`; @@ -352,6 +378,8 @@ exports[`Transaction HTTP_RESPONSE_STATUS_CODE 1`] = `200`; exports[`Transaction LABEL_NAME 1`] = `undefined`; +exports[`Transaction LCP_FIELD 1`] = `undefined`; + exports[`Transaction METRIC_JAVA_GC_COUNT 1`] = `undefined`; exports[`Transaction METRIC_JAVA_GC_TIME 1`] = `undefined`; @@ -426,6 +454,8 @@ exports[`Transaction SPAN_SUBTYPE 1`] = `undefined`; exports[`Transaction SPAN_TYPE 1`] = `undefined`; +exports[`Transaction TBT_FIELD 1`] = `undefined`; + exports[`Transaction TRACE_ID 1`] = `"trace id"`; exports[`Transaction TRANSACTION_BREAKDOWN_COUNT 1`] = `undefined`; @@ -448,7 +478,7 @@ exports[`Transaction TRANSACTION_TIME_TO_FIRST_BYTE 1`] = `undefined`; exports[`Transaction TRANSACTION_TYPE 1`] = `"transaction type"`; -exports[`Transaction TRANSACTION_URL 1`] = `undefined`; +exports[`Transaction TRANSACTION_URL 1`] = `"http://www.elastic.co"`; exports[`Transaction URL_FULL 1`] = `"http://www.elastic.co"`; diff --git a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts index c13169549a56..e1a279714d30 100644 --- a/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts +++ b/x-pack/plugins/apm/common/elasticsearch_fieldnames.ts @@ -97,7 +97,7 @@ export const POD_NAME = 'kubernetes.pod.name'; export const CLIENT_GEO_COUNTRY_ISO_CODE = 'client.geo.country_iso_code'; // RUM Labels -export const TRANSACTION_URL = 'transaction.page.url'; +export const TRANSACTION_URL = 'url.full'; export const CLIENT_GEO = 'client.geo'; export const USER_AGENT_DEVICE = 'user_agent.device.name'; export const USER_AGENT_OS = 'user_agent.os.name'; @@ -106,3 +106,9 @@ export const TRANSACTION_TIME_TO_FIRST_BYTE = 'transaction.marks.agent.timeToFirstByte'; export const TRANSACTION_DOM_INTERACTIVE = 'transaction.marks.agent.domInteractive'; + +export const FCP_FIELD = 'transaction.marks.agent.firstContentfulPaint'; +export const LCP_FIELD = 'transaction.marks.agent.largestContentfulPaint'; +export const TBT_FIELD = 'transaction.experience.tbt'; +export const FID_FIELD = 'transaction.experience.fid'; +export const CLS_FIELD = 'transaction.experience.cls'; diff --git a/x-pack/plugins/apm/dev_docs/routing_and_linking.md b/x-pack/plugins/apm/dev_docs/routing_and_linking.md new file mode 100644 index 000000000000..d27513d44935 --- /dev/null +++ b/x-pack/plugins/apm/dev_docs/routing_and_linking.md @@ -0,0 +1,38 @@ +# APM Plugin Routing and Linking + +## Routing + +This document describes routing in the APM plugin. + +### Server-side + +Route definitions for APM's server-side API are in the [server/routes directory](../server/routes). Routes are created with [the `createRoute` function](../server/routes/create_route.ts). Routes are added to the API in [the `createApmApi` function](../server/routes/create_apm_api.ts), which is initialized in the plugin `start` lifecycle method. + +The path and query string parameters are defined in the calls to `createRoute` with io-ts types, so that each route has its parameters type checked. + +### Client-side + +The client-side routing uses [React Router](https://reactrouter.com/), The [`ApmRoute` component from the Elastic RUM Agent](https://www.elastic.co/guide/en/apm/agent/rum-js/current/react-integration.html), and the `history` object provided by the Kibana Platform. + +Routes are defined in [public/components/app/Main/route_config/index.tsx](../public/components/app/Main/route_config/index.tsx). These contain route definitions as well as the breadcrumb text. + +#### Parameter handling + +Path parameters (like `serviceName` in '/services/:serviceName/transactions') are handled by the `match.params` props passed into +routes by React Router. The types of these parameters are defined in the route definitions. + +If the parameters are not available as props you can use React Router's `useParams`, but their type definitions should be delcared inline and it's a good idea to make the properties optional if you don't know where a component will be used, since those parameters might not be available at that route. + +Query string parameters can be used in any component with `useUrlParams`. All of the available parameters are defined by this hook and its context. + +## Linking + +Raw URLs should almost never be used in the APM UI. Instead, we have mechanisms for creating links and URLs that ensure links are reliable. + +### In-app linking + +Links that stay inside APM should use the [`getAPMHref` function and `APMLink` component](../public/components/shared/Links/apm/APMLink.tsx). Other components inside that directory contain other functions and components that provide the same functionality for linking to more specific sections inside the APM plugin. + +### Cross-app linking + +Other helpers and components in [the Links directory](../public/components/shared/Links) allow linking to other Kibana apps. diff --git a/x-pack/plugins/apm/dev_docs/updating_functional_tests_archives.md b/x-pack/plugins/apm/dev_docs/updating_functional_tests_archives.md new file mode 100644 index 000000000000..467090fb3c91 --- /dev/null +++ b/x-pack/plugins/apm/dev_docs/updating_functional_tests_archives.md @@ -0,0 +1,8 @@ +### Updating functional tests archives + +Some of our API tests use an archive generated by the [`esarchiver`](https://www.elastic.co/guide/en/kibana/current/development-functional-tests.html) script. Updating the main archive (`apm_8.0.0`) is a scripted process, where a 30m snapshot is downloaded from a cluster running the [APM Integration Testing server](https://github.com/elastic/apm-integration-testing). The script will copy the generated archives into the `fixtures/es_archiver` folders of our test suites (currently `basic` and `trial`). It will also generate a file that contains metadata about the archive, that can be imported to get the time range of the snapshot. + +Usage: +`node x-pack/plugins/apm/scripts/create-functional-tests-archive --es-url=https://admin:changeme@localhost:9200 --kibana-url=https://localhost:5601` + + diff --git a/x-pack/plugins/apm/public/application/csmApp.tsx b/x-pack/plugins/apm/public/application/csmApp.tsx index d76ed5c2100b..cdfe42bd628c 100644 --- a/x-pack/plugins/apm/public/application/csmApp.tsx +++ b/x-pack/plugins/apm/public/application/csmApp.tsx @@ -4,52 +4,51 @@ * you may not use this file except in compliance with the Elastic License. */ +import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; +import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import { AppMountParameters, CoreStart } from 'kibana/public'; import React from 'react'; import ReactDOM from 'react-dom'; import { Route, Router } from 'react-router-dom'; -import styled, { ThemeProvider, DefaultTheme } from 'styled-components'; -import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; -import { CoreStart, AppMountParameters } from 'kibana/public'; -import { ApmPluginSetupDeps } from '../plugin'; - +import 'react-vis/dist/style.css'; +import styled, { DefaultTheme, ThemeProvider } from 'styled-components'; import { KibanaContextProvider, - useUiSetting$, RedirectAppLinks, + useUiSetting$, } from '../../../../../src/plugins/kibana_react/public'; -import { px, units } from '../style/variables'; -import { UpdateBreadcrumbs } from '../components/app/Main/UpdateBreadcrumbs'; +import { APMRouteDefinition } from '../application/routes'; +import { renderAsRedirectTo } from '../components/app/Main/route_config'; import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange'; -import 'react-vis/dist/style.css'; import { RumHome } from '../components/app/RumDashboard/RumHome'; -import { ConfigSchema } from '../index'; -import { BreadcrumbRoute } from '../components/app/Main/ProvideBreadcrumbs'; -import { RouteName } from '../components/app/Main/route_config/route_names'; -import { renderAsRedirectTo } from '../components/app/Main/route_config'; import { ApmPluginContext } from '../context/ApmPluginContext'; -import { UrlParamsProvider } from '../context/UrlParamsContext'; import { LoadingIndicatorProvider } from '../context/LoadingIndicatorContext'; +import { UrlParamsProvider } from '../context/UrlParamsContext'; +import { useBreadcrumbs } from '../hooks/use_breadcrumbs'; +import { ConfigSchema } from '../index'; +import { ApmPluginSetupDeps } from '../plugin'; import { createCallApmApi } from '../services/rest/createCallApmApi'; +import { px, units } from '../style/variables'; const CsmMainContainer = styled.div` padding: ${px(units.plus)}; height: 100%; `; -export const rumRoutes: BreadcrumbRoute[] = [ +export const rumRoutes: APMRouteDefinition[] = [ { exact: true, path: '/', render: renderAsRedirectTo('/csm'), breadcrumb: 'Client Side Monitoring', - name: RouteName.CSM, }, ]; function CsmApp() { const [darkMode] = useUiSetting$('theme:darkMode'); + useBreadcrumbs(rumRoutes); + return ( ({ @@ -59,7 +58,6 @@ function CsmApp() { })} > - diff --git a/x-pack/plugins/apm/public/application/index.tsx b/x-pack/plugins/apm/public/application/index.tsx index 2b0b3ddd9816..536d70b053f7 100644 --- a/x-pack/plugins/apm/public/application/index.tsx +++ b/x-pack/plugins/apm/public/application/index.tsx @@ -22,12 +22,12 @@ import { import { AlertsContextProvider } from '../../../triggers_actions_ui/public'; import { routes } from '../components/app/Main/route_config'; import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange'; -import { UpdateBreadcrumbs } from '../components/app/Main/UpdateBreadcrumbs'; import { ApmPluginContext } from '../context/ApmPluginContext'; import { LicenseProvider } from '../context/LicenseContext'; import { LoadingIndicatorProvider } from '../context/LoadingIndicatorContext'; import { LocationProvider } from '../context/LocationContext'; import { UrlParamsProvider } from '../context/UrlParamsContext'; +import { useBreadcrumbs } from '../hooks/use_breadcrumbs'; import { ApmPluginSetupDeps } from '../plugin'; import { createCallApmApi } from '../services/rest/createCallApmApi'; import { createStaticIndexPattern } from '../services/rest/index_pattern'; @@ -43,6 +43,8 @@ const MainContainer = styled.div` function App() { const [darkMode] = useUiSetting$('theme:darkMode'); + useBreadcrumbs(routes); + return ( ({ @@ -52,7 +54,6 @@ function App() { })} > - {routes.map((route, i) => ( diff --git a/x-pack/plugins/apm/public/application/routes/index.tsx b/x-pack/plugins/apm/public/application/routes/index.tsx new file mode 100644 index 000000000000..d1bb8ae8fc8a --- /dev/null +++ b/x-pack/plugins/apm/public/application/routes/index.tsx @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { RouteComponentProps, RouteProps } from 'react-router-dom'; + +export type BreadcrumbTitle = + | string + | ((props: RouteComponentProps) => string) + | null; + +export interface APMRouteDefinition extends RouteProps { + breadcrumb: BreadcrumbTitle; +} diff --git a/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx index 31f299f94bc2..e95d35142684 100644 --- a/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx @@ -15,11 +15,11 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { Fragment } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; import styled from 'styled-components'; import { useTrackPageview } from '../../../../../observability/public'; import { NOT_AVAILABLE_LABEL } from '../../../../common/i18n'; import { useFetcher } from '../../../hooks/useFetcher'; -import { useLocation } from '../../../hooks/useLocation'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { callApmApi } from '../../../services/rest/createCallApmApi'; import { fontFamilyCode, fontSizes, px, units } from '../../../style/variables'; @@ -56,19 +56,24 @@ function getShortGroupId(errorGroupId?: string) { return errorGroupId.slice(0, 5); } -export function ErrorGroupDetails() { - const location = useLocation(); +type ErrorGroupDetailsProps = RouteComponentProps<{ + groupId: string; + serviceName: string; +}>; + +export function ErrorGroupDetails({ location, match }: ErrorGroupDetailsProps) { + const { serviceName, groupId } = match.params; const { urlParams, uiFilters } = useUrlParams(); - const { serviceName, start, end, errorGroupId } = urlParams; + const { start, end } = urlParams; const { data: errorGroupData } = useFetcher(() => { - if (serviceName && start && end && errorGroupId) { + if (start && end) { return callApmApi({ pathname: '/api/apm/services/{serviceName}/errors/{groupId}', params: { path: { serviceName, - groupId: errorGroupId, + groupId, }, query: { start, @@ -78,10 +83,10 @@ export function ErrorGroupDetails() { }, }); } - }, [serviceName, start, end, errorGroupId, uiFilters]); + }, [serviceName, start, end, groupId, uiFilters]); const { data: errorDistributionData } = useFetcher(() => { - if (serviceName && start && end && errorGroupId) { + if (start && end) { return callApmApi({ pathname: '/api/apm/services/{serviceName}/errors/distribution', params: { @@ -91,13 +96,13 @@ export function ErrorGroupDetails() { query: { start, end, - groupId: errorGroupId, + groupId, uiFilters: JSON.stringify(uiFilters), }, }, }); } - }, [serviceName, start, end, errorGroupId, uiFilters]); + }, [serviceName, start, end, groupId, uiFilters]); useTrackPageview({ app: 'apm', path: 'error_group_details' }); useTrackPageview({ app: 'apm', path: 'error_group_details', delay: 15000 }); @@ -124,7 +129,7 @@ export function ErrorGroupDetails() { {i18n.translate('xpack.apm.errorGroupDetails.errorGroupTitle', { defaultMessage: 'Error group {errorGroupId}', values: { - errorGroupId: getShortGroupId(urlParams.errorGroupId), + errorGroupId: getShortGroupId(groupId), }, })} diff --git a/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/List.test.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/List.test.tsx index 5798deaf19c9..1acfc5c49245 100644 --- a/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/List.test.tsx +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/List.test.tsx @@ -27,7 +27,7 @@ describe('ErrorGroupOverview -> List', () => { const storeState = {}; const wrapper = mount( - + , storeState ); @@ -39,7 +39,7 @@ describe('ErrorGroupOverview -> List', () => { const wrapper = mount( - + ); diff --git a/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx index 5c16bf0f324b..33105189f9c3 100644 --- a/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx @@ -51,16 +51,12 @@ const Culprit = styled.div` interface Props { items: ErrorGroupListAPIResponse; + serviceName: string; } -function ErrorGroupList(props: Props) { - const { items } = props; +function ErrorGroupList({ items, serviceName }: Props) { const { urlParams } = useUrlParams(); - const { serviceName } = urlParams; - if (!serviceName) { - throw new Error('Service name is required'); - } const columns = useMemo( () => [ { diff --git a/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx index 92ea04472053..42b0016ca8cf 100644 --- a/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx @@ -22,13 +22,17 @@ import { LocalUIFilters } from '../../shared/LocalUIFilters'; import { ErrorDistribution } from '../ErrorGroupDetails/Distribution'; import { ErrorGroupList } from './List'; -function ErrorGroupOverview() { +interface ErrorGroupOverviewProps { + serviceName: string; +} + +function ErrorGroupOverview({ serviceName }: ErrorGroupOverviewProps) { const { urlParams, uiFilters } = useUrlParams(); - const { serviceName, start, end, sortField, sortDirection } = urlParams; + const { start, end, sortField, sortDirection } = urlParams; const { data: errorDistributionData } = useFetcher(() => { - if (serviceName && start && end) { + if (start && end) { return callApmApi({ pathname: '/api/apm/services/{serviceName}/errors/distribution', params: { @@ -48,7 +52,7 @@ function ErrorGroupOverview() { const { data: errorGroupListData } = useFetcher(() => { const normalizedSortDirection = sortDirection === 'asc' ? 'asc' : 'desc'; - if (serviceName && start && end) { + if (start && end) { return callApmApi({ pathname: '/api/apm/services/{serviceName}/errors', params: { @@ -117,7 +121,10 @@ function ErrorGroupOverview() { - + diff --git a/x-pack/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap b/x-pack/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap index 24b51e3fba91..9706895b164a 100644 --- a/x-pack/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap +++ b/x-pack/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap @@ -18,6 +18,7 @@ exports[`Home component should render services 1`] = ` "currentAppId$": Observable { "_isScalar": false, }, + "navigateToUrl": [Function], }, "chrome": Object { "docTitle": Object { @@ -78,6 +79,7 @@ exports[`Home component should render traces 1`] = ` "currentAppId$": Observable { "_isScalar": false, }, + "navigateToUrl": [Function], }, "chrome": Object { "docTitle": Object { diff --git a/x-pack/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.test.tsx b/x-pack/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.test.tsx deleted file mode 100644 index bf1cd75432ff..000000000000 --- a/x-pack/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.test.tsx +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Location } from 'history'; -import { BreadcrumbRoute, getBreadcrumbs } from './ProvideBreadcrumbs'; -import { RouteName } from './route_config/route_names'; - -describe('getBreadcrumbs', () => { - const getTestRoutes = (): BreadcrumbRoute[] => [ - { path: '/a', exact: true, breadcrumb: 'A', name: RouteName.HOME }, - { - path: '/a/ignored', - exact: true, - breadcrumb: 'Ignored Route', - name: RouteName.METRICS, - }, - { - path: '/a/:letter', - exact: true, - name: RouteName.SERVICE, - breadcrumb: ({ match }) => `Second level: ${match.params.letter}`, - }, - { - path: '/a/:letter/c', - exact: true, - name: RouteName.ERRORS, - breadcrumb: ({ match }) => `Third level: ${match.params.letter}`, - }, - ]; - - const getLocation = () => - ({ - pathname: '/a/b/c/', - } as Location); - - it('should return a set of matching breadcrumbs for a given path', () => { - const breadcrumbs = getBreadcrumbs({ - location: getLocation(), - routes: getTestRoutes(), - }); - - expect(breadcrumbs.map((b) => b.value)).toMatchInlineSnapshot(` -Array [ - "A", - "Second level: b", - "Third level: b", -] -`); - }); - - it('should skip breadcrumbs if breadcrumb is null', () => { - const location = getLocation(); - const routes = getTestRoutes(); - - routes[2].breadcrumb = null; - - const breadcrumbs = getBreadcrumbs({ - location, - routes, - }); - - expect(breadcrumbs.map((b) => b.value)).toMatchInlineSnapshot(` -Array [ - "A", - "Third level: b", -] -`); - }); - - it('should skip breadcrumbs if breadcrumb key is missing', () => { - const location = getLocation(); - const routes = getTestRoutes(); - - // @ts-expect-error - delete routes[2].breadcrumb; - - const breadcrumbs = getBreadcrumbs({ location, routes }); - - expect(breadcrumbs.map((b) => b.value)).toMatchInlineSnapshot(` -Array [ - "A", - "Third level: b", -] -`); - }); - - it('should produce matching breadcrumbs even if the pathname has a query string appended', () => { - const location = getLocation(); - const routes = getTestRoutes(); - - location.pathname += '?some=thing'; - - const breadcrumbs = getBreadcrumbs({ - location, - routes, - }); - - expect(breadcrumbs.map((b) => b.value)).toMatchInlineSnapshot(` -Array [ - "A", - "Second level: b", - "Third level: b", -] -`); - }); -}); diff --git a/x-pack/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.tsx b/x-pack/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.tsx deleted file mode 100644 index f2505b64fb1e..000000000000 --- a/x-pack/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.tsx +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Location } from 'history'; -import React from 'react'; -import { - matchPath, - RouteComponentProps, - RouteProps, - withRouter, -} from 'react-router-dom'; -import { RouteName } from './route_config/route_names'; - -type LocationMatch = Pick< - RouteComponentProps>, - 'location' | 'match' ->; - -type BreadcrumbFunction = (props: LocationMatch) => string; - -export interface BreadcrumbRoute extends RouteProps { - breadcrumb: string | BreadcrumbFunction | null; - name: RouteName; -} - -export interface Breadcrumb extends LocationMatch { - value: string; -} - -interface RenderProps extends RouteComponentProps { - breadcrumbs: Breadcrumb[]; -} - -interface ProvideBreadcrumbsProps extends RouteComponentProps { - routes: BreadcrumbRoute[]; - render: (props: RenderProps) => React.ReactElement | null; -} - -interface ParseOptions extends LocationMatch { - breadcrumb: string | BreadcrumbFunction; -} - -const parse = (options: ParseOptions) => { - const { breadcrumb, match, location } = options; - let value; - - if (typeof breadcrumb === 'function') { - value = breadcrumb({ match, location }); - } else { - value = breadcrumb; - } - - return { value, match, location }; -}; - -export function getBreadcrumb({ - location, - currentPath, - routes, -}: { - location: Location; - currentPath: string; - routes: BreadcrumbRoute[]; -}) { - return routes.reduce((found, { breadcrumb, ...route }) => { - if (found) { - return found; - } - - if (!breadcrumb) { - return null; - } - - const match = matchPath>(currentPath, route); - - if (match) { - return parse({ - breadcrumb, - match, - location, - }); - } - - return null; - }, null); -} - -export function getBreadcrumbs({ - routes, - location, -}: { - routes: BreadcrumbRoute[]; - location: Location; -}) { - const breadcrumbs: Breadcrumb[] = []; - const { pathname } = location; - - pathname - .split('?')[0] - .replace(/\/$/, '') - .split('/') - .reduce((acc, next) => { - // `/1/2/3` results in match checks for `/1`, `/1/2`, `/1/2/3`. - const currentPath = !next ? '/' : `${acc}/${next}`; - const breadcrumb = getBreadcrumb({ - location, - currentPath, - routes, - }); - - if (breadcrumb) { - breadcrumbs.push(breadcrumb); - } - - return currentPath === '/' ? '' : currentPath; - }, ''); - - return breadcrumbs; -} - -function ProvideBreadcrumbsComponent({ - routes = [], - render, - location, - match, - history, -}: ProvideBreadcrumbsProps) { - const breadcrumbs = getBreadcrumbs({ routes, location }); - return render({ breadcrumbs, location, match, history }); -} - -export const ProvideBreadcrumbs = withRouter(ProvideBreadcrumbsComponent); diff --git a/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx b/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx deleted file mode 100644 index 5bf5cea587f9..000000000000 --- a/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx +++ /dev/null @@ -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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Location } from 'history'; -import React, { MouseEvent } from 'react'; -import { CoreStart } from 'src/core/public'; -import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; -import { getAPMHref } from '../../shared/Links/apm/APMLink'; -import { - Breadcrumb, - BreadcrumbRoute, - ProvideBreadcrumbs, -} from './ProvideBreadcrumbs'; - -interface Props { - location: Location; - breadcrumbs: Breadcrumb[]; - core: CoreStart; -} - -function getTitleFromBreadCrumbs(breadcrumbs: Breadcrumb[]) { - return breadcrumbs.map(({ value }) => value).reverse(); -} - -class UpdateBreadcrumbsComponent extends React.Component { - public updateHeaderBreadcrumbs() { - const { basePath } = this.props.core.http; - const breadcrumbs = this.props.breadcrumbs.map( - ({ value, match }, index) => { - const { search } = this.props.location; - const isLastBreadcrumbItem = - index === this.props.breadcrumbs.length - 1; - const href = isLastBreadcrumbItem - ? undefined // makes the breadcrumb item not clickable - : getAPMHref({ basePath, path: match.url, search }); - return { - text: value, - href, - onClick: (event: MouseEvent) => { - if (href) { - event.preventDefault(); - this.props.core.application.navigateToUrl(href); - } - }, - }; - } - ); - - this.props.core.chrome.docTitle.change( - getTitleFromBreadCrumbs(this.props.breadcrumbs) - ); - this.props.core.chrome.setBreadcrumbs(breadcrumbs); - } - - public componentDidMount() { - this.updateHeaderBreadcrumbs(); - } - - public componentDidUpdate() { - this.updateHeaderBreadcrumbs(); - } - - public render() { - return null; - } -} - -interface UpdateBreadcrumbsProps { - routes: BreadcrumbRoute[]; -} - -export function UpdateBreadcrumbs({ routes }: UpdateBreadcrumbsProps) { - const { core } = useApmPluginContext(); - - return ( - ( - - )} - /> - ); -} diff --git a/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx b/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx index 56026dcf477e..0cefcbdc5422 100644 --- a/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx @@ -7,38 +7,32 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { Redirect, RouteComponentProps } from 'react-router-dom'; +import { UNIDENTIFIED_SERVICE_NODES_LABEL } from '../../../../../common/i18n'; import { SERVICE_NODE_NAME_MISSING } from '../../../../../common/service_nodes'; +import { APMRouteDefinition } from '../../../../application/routes'; +import { toQuery } from '../../../shared/Links/url_helpers'; import { ErrorGroupDetails } from '../../ErrorGroupDetails'; -import { ServiceDetails } from '../../ServiceDetails'; -import { TransactionDetails } from '../../TransactionDetails'; import { Home } from '../../Home'; -import { BreadcrumbRoute } from '../ProvideBreadcrumbs'; -import { RouteName } from './route_names'; +import { ServiceDetails } from '../../ServiceDetails'; +import { ServiceNodeMetrics } from '../../ServiceNodeMetrics'; import { Settings } from '../../Settings'; import { AgentConfigurations } from '../../Settings/AgentConfigurations'; +import { AnomalyDetection } from '../../Settings/anomaly_detection'; import { ApmIndices } from '../../Settings/ApmIndices'; -import { toQuery } from '../../../shared/Links/url_helpers'; -import { ServiceNodeMetrics } from '../../ServiceNodeMetrics'; -import { resolveUrlParams } from '../../../../context/UrlParamsContext/resolveUrlParams'; -import { UNIDENTIFIED_SERVICE_NODES_LABEL } from '../../../../../common/i18n'; -import { TraceLink } from '../../TraceLink'; import { CustomizeUI } from '../../Settings/CustomizeUI'; -import { AnomalyDetection } from '../../Settings/anomaly_detection'; +import { TraceLink } from '../../TraceLink'; +import { TransactionDetails } from '../../TransactionDetails'; import { CreateAgentConfigurationRouteHandler, EditAgentConfigurationRouteHandler, } from './route_handlers/agent_configuration'; -const metricsBreadcrumb = i18n.translate('xpack.apm.breadcrumb.metricsTitle', { - defaultMessage: 'Metrics', -}); - -interface RouteParams { - serviceName: string; -} - -export const renderAsRedirectTo = (to: string) => { - return ({ location }: RouteComponentProps) => { +/** + * Given a path, redirect to that location, preserving the search and maintaining + * backward-compatibilty with legacy (pre-7.9) hash-based URLs. + */ +export function renderAsRedirectTo(to: string) { + return ({ location }: RouteComponentProps<{}>) => { let resolvedUrl: URL | undefined; // Redirect root URLs with a hash to support backward compatibility with URLs @@ -60,71 +54,149 @@ export const renderAsRedirectTo = (to: string) => { /> ); }; -}; +} + +// These component function definitions are used below with the `component` +// property of the route definitions. +// +// If you provide an inline function to the component prop, you would create a +// new component every render. This results in the existing component unmounting +// and the new component mounting instead of just updating the existing component. +// +// This means you should use `render` if you're providing an inline function. +// However, the `ApmRoute` component from @elastic/apm-rum-react, only supports +// `component`, and will give you a large console warning if you use `render`. +// +// This warning cannot be turned off +// (see https://github.com/elastic/apm-agent-rum-js/issues/881) so while this is +// slightly more code, it provides better performance without causing console +// warnings to appear. +function HomeServices() { + return ; +} + +function HomeServiceMap() { + return ; +} + +function HomeTraces() { + return ; +} + +function ServiceDetailsErrors( + props: RouteComponentProps<{ serviceName: string }> +) { + return ; +} -export const routes: BreadcrumbRoute[] = [ +function ServiceDetailsMetrics( + props: RouteComponentProps<{ serviceName: string }> +) { + return ; +} + +function ServiceDetailsNodes( + props: RouteComponentProps<{ serviceName: string }> +) { + return ; +} + +function ServiceDetailsServiceMap( + props: RouteComponentProps<{ serviceName: string }> +) { + return ; +} + +function ServiceDetailsTransactions( + props: RouteComponentProps<{ serviceName: string }> +) { + return ; +} + +function SettingsAgentConfiguration() { + return ( + + + + ); +} + +function SettingsAnomalyDetection() { + return ( + + + + ); +} + +function SettingsApmIndices() { + return ( + + + + ); +} + +function SettingsCustomizeUI() { + return ( + + + + ); +} + +/** + * The array of route definitions to be used when the application + * creates the routes. + */ +export const routes: APMRouteDefinition[] = [ { exact: true, path: '/', - render: renderAsRedirectTo('/services'), + component: renderAsRedirectTo('/services'), breadcrumb: 'APM', - name: RouteName.HOME, }, { exact: true, path: '/services', - component: () => , + component: HomeServices, breadcrumb: i18n.translate('xpack.apm.breadcrumb.servicesTitle', { defaultMessage: 'Services', }), - name: RouteName.SERVICES, }, { exact: true, path: '/traces', - component: () => , + component: HomeTraces, breadcrumb: i18n.translate('xpack.apm.breadcrumb.tracesTitle', { defaultMessage: 'Traces', }), - name: RouteName.TRACES, }, { exact: true, path: '/settings', - render: renderAsRedirectTo('/settings/agent-configuration'), + component: renderAsRedirectTo('/settings/agent-configuration'), breadcrumb: i18n.translate('xpack.apm.breadcrumb.listSettingsTitle', { defaultMessage: 'Settings', }), - name: RouteName.SETTINGS, }, { exact: true, path: '/settings/apm-indices', - component: () => ( - - - - ), + component: SettingsApmIndices, breadcrumb: i18n.translate('xpack.apm.breadcrumb.settings.indicesTitle', { defaultMessage: 'Indices', }), - name: RouteName.INDICES, }, { exact: true, path: '/settings/agent-configuration', - component: () => ( - - - - ), + component: SettingsAgentConfiguration, breadcrumb: i18n.translate( 'xpack.apm.breadcrumb.settings.agentConfigurationTitle', { defaultMessage: 'Agent Configuration' } ), - name: RouteName.AGENT_CONFIGURATION, }, - { exact: true, path: '/settings/agent-configuration/create', @@ -132,8 +204,7 @@ export const routes: BreadcrumbRoute[] = [ 'xpack.apm.breadcrumb.settings.createAgentConfigurationTitle', { defaultMessage: 'Create Agent Configuration' } ), - name: RouteName.AGENT_CONFIGURATION_CREATE, - component: () => , + component: CreateAgentConfigurationRouteHandler, }, { exact: true, @@ -142,71 +213,66 @@ export const routes: BreadcrumbRoute[] = [ 'xpack.apm.breadcrumb.settings.editAgentConfigurationTitle', { defaultMessage: 'Edit Agent Configuration' } ), - name: RouteName.AGENT_CONFIGURATION_EDIT, - component: () => , + component: EditAgentConfigurationRouteHandler, }, { exact: true, path: '/services/:serviceName', breadcrumb: ({ match }) => match.params.serviceName, - render: (props: RouteComponentProps) => + component: (props: RouteComponentProps<{ serviceName: string }>) => renderAsRedirectTo( `/services/${props.match.params.serviceName}/transactions` )(props), - name: RouteName.SERVICE, - }, + } as APMRouteDefinition<{ serviceName: string }>, // errors { exact: true, path: '/services/:serviceName/errors/:groupId', component: ErrorGroupDetails, breadcrumb: ({ match }) => match.params.groupId, - name: RouteName.ERROR, - }, + } as APMRouteDefinition<{ groupId: string; serviceName: string }>, { exact: true, path: '/services/:serviceName/errors', - component: () => , + component: ServiceDetailsErrors, breadcrumb: i18n.translate('xpack.apm.breadcrumb.errorsTitle', { defaultMessage: 'Errors', }), - name: RouteName.ERRORS, }, // transactions { exact: true, path: '/services/:serviceName/transactions', - component: () => , + component: ServiceDetailsTransactions, breadcrumb: i18n.translate('xpack.apm.breadcrumb.transactionsTitle', { defaultMessage: 'Transactions', }), - name: RouteName.TRANSACTIONS, }, // metrics { exact: true, path: '/services/:serviceName/metrics', - component: () => , - breadcrumb: metricsBreadcrumb, - name: RouteName.METRICS, + component: ServiceDetailsMetrics, + breadcrumb: i18n.translate('xpack.apm.breadcrumb.metricsTitle', { + defaultMessage: 'Metrics', + }), }, // service nodes, only enabled for java agents for now { exact: true, path: '/services/:serviceName/nodes', - component: () => , + component: ServiceDetailsNodes, breadcrumb: i18n.translate('xpack.apm.breadcrumb.nodesTitle', { defaultMessage: 'JVMs', }), - name: RouteName.SERVICE_NODES, }, // node metrics { exact: true, path: '/services/:serviceName/nodes/:serviceNodeName/metrics', - component: () => , - breadcrumb: ({ location }) => { - const { serviceNodeName } = resolveUrlParams(location, {}); + component: ServiceNodeMetrics, + breadcrumb: ({ match }) => { + const { serviceNodeName } = match.params; if (serviceNodeName === SERVICE_NODE_NAME_MISSING) { return UNIDENTIFIED_SERVICE_NODES_LABEL; @@ -214,7 +280,6 @@ export const routes: BreadcrumbRoute[] = [ return serviceNodeName || ''; }, - name: RouteName.SERVICE_NODE_METRICS, }, { exact: true, @@ -224,61 +289,46 @@ export const routes: BreadcrumbRoute[] = [ const query = toQuery(location.search); return query.transactionName as string; }, - name: RouteName.TRANSACTION_NAME, }, { exact: true, path: '/link-to/trace/:traceId', component: TraceLink, breadcrumb: null, - name: RouteName.LINK_TO_TRACE, }, - { exact: true, path: '/service-map', - component: () => , + component: HomeServiceMap, breadcrumb: i18n.translate('xpack.apm.breadcrumb.serviceMapTitle', { defaultMessage: 'Service Map', }), - name: RouteName.SERVICE_MAP, }, { exact: true, path: '/services/:serviceName/service-map', - component: () => , + component: ServiceDetailsServiceMap, breadcrumb: i18n.translate('xpack.apm.breadcrumb.serviceMapTitle', { defaultMessage: 'Service Map', }), - name: RouteName.SINGLE_SERVICE_MAP, }, { exact: true, path: '/settings/customize-ui', - component: () => ( - - - - ), + component: SettingsCustomizeUI, breadcrumb: i18n.translate('xpack.apm.breadcrumb.settings.customizeUI', { defaultMessage: 'Customize UI', }), - name: RouteName.CUSTOMIZE_UI, }, { exact: true, path: '/settings/anomaly-detection', - component: () => ( - - - - ), + component: SettingsAnomalyDetection, breadcrumb: i18n.translate( 'xpack.apm.breadcrumb.settings.anomalyDetection', { defaultMessage: 'Anomaly detection', } ), - name: RouteName.ANOMALY_DETECTION, }, ]; diff --git a/x-pack/plugins/apm/public/components/app/Main/route_config/route_config.test.tsx b/x-pack/plugins/apm/public/components/app/Main/route_config/route_config.test.tsx index ad12afe35fa2..21a162111bc7 100644 --- a/x-pack/plugins/apm/public/components/app/Main/route_config/route_config.test.tsx +++ b/x-pack/plugins/apm/public/components/app/Main/route_config/route_config.test.tsx @@ -14,7 +14,7 @@ describe('routes', () => { it('redirects to /services', () => { const location = { hash: '', pathname: '/', search: '' }; expect( - (route as any).render({ location } as any).props.to.pathname + (route as any).component({ location } as any).props.to.pathname ).toEqual('/services'); }); }); @@ -28,7 +28,9 @@ describe('routes', () => { search: '', }; - expect(((route as any).render({ location }) as any).props.to).toEqual({ + expect( + ((route as any).component({ location }) as any).props.to + ).toEqual({ hash: '', pathname: '/services/opbeans-python/transactions/view', search: diff --git a/x-pack/plugins/apm/public/components/app/Main/route_config/route_handlers/agent_configuration.tsx b/x-pack/plugins/apm/public/components/app/Main/route_config/route_handlers/agent_configuration.tsx index 7a00840daa3c..cc0728645790 100644 --- a/x-pack/plugins/apm/public/components/app/Main/route_config/route_handlers/agent_configuration.tsx +++ b/x-pack/plugins/apm/public/components/app/Main/route_config/route_handlers/agent_configuration.tsx @@ -5,14 +5,17 @@ */ import React from 'react'; -import { useHistory } from 'react-router-dom'; +import { RouteComponentProps } from 'react-router-dom'; import { useFetcher } from '../../../../../hooks/useFetcher'; import { toQuery } from '../../../../shared/Links/url_helpers'; import { Settings } from '../../../Settings'; import { AgentConfigurationCreateEdit } from '../../../Settings/AgentConfigurations/AgentConfigurationCreateEdit'; -export function EditAgentConfigurationRouteHandler() { - const history = useHistory(); +type EditAgentConfigurationRouteHandler = RouteComponentProps<{}>; + +export function EditAgentConfigurationRouteHandler({ + history, +}: EditAgentConfigurationRouteHandler) { const { search } = history.location; // typescript complains because `pageStop` does not exist in `APMQueryParams` @@ -40,8 +43,11 @@ export function EditAgentConfigurationRouteHandler() { ); } -export function CreateAgentConfigurationRouteHandler() { - const history = useHistory(); +type CreateAgentConfigurationRouteHandlerProps = RouteComponentProps<{}>; + +export function CreateAgentConfigurationRouteHandler({ + history, +}: CreateAgentConfigurationRouteHandlerProps) { const { search } = history.location; // Ignoring here because we specifically DO NOT want to add the query params to the global route handler diff --git a/x-pack/plugins/apm/public/components/app/Main/route_config/route_names.tsx b/x-pack/plugins/apm/public/components/app/Main/route_config/route_names.tsx deleted file mode 100644 index 1bf798e3b26d..000000000000 --- a/x-pack/plugins/apm/public/components/app/Main/route_config/route_names.tsx +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -export enum RouteName { - HOME = 'home', - SERVICES = 'services', - SERVICE_MAP = 'service-map', - SINGLE_SERVICE_MAP = 'single-service-map', - TRACES = 'traces', - SERVICE = 'service', - TRANSACTIONS = 'transactions', - ERRORS = 'errors', - ERROR = 'error', - METRICS = 'metrics', - SERVICE_NODE_METRICS = 'node_metrics', - TRANSACTION_TYPE = 'transaction_type', - TRANSACTION_NAME = 'transaction_name', - SETTINGS = 'settings', - AGENT_CONFIGURATION = 'agent_configuration', - AGENT_CONFIGURATION_CREATE = 'agent_configuration_create', - AGENT_CONFIGURATION_EDIT = 'agent_configuration_edit', - INDICES = 'indices', - SERVICE_NODES = 'nodes', - LINK_TO_TRACE = 'link_to_trace', - CUSTOMIZE_UI = 'customize_ui', - ANOMALY_DETECTION = 'anomaly_detection', - CSM = 'csm', -} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ChartWrapper/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ChartWrapper/index.tsx index 970365779a0a..f27a3d56aab5 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ChartWrapper/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ChartWrapper/index.tsx @@ -26,11 +26,14 @@ interface Props { * aria-label for accessibility */ 'aria-label'?: string; + + maxWidth?: string; } export function ChartWrapper({ loading = false, height = '100%', + maxWidth, children, ...rest }: Props) { @@ -43,6 +46,7 @@ export function ChartWrapper({ height, opacity, transition: 'opacity 0.2s', + ...(maxWidth ? { maxWidth } : {}), }} {...(rest as HTMLAttributes)} > @@ -52,7 +56,12 @@ export function ChartWrapper({ diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/VisitorBreakdownChart.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/VisitorBreakdownChart.tsx index 9f9ffdf7168b..213126ba4bf8 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/VisitorBreakdownChart.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/Charts/VisitorBreakdownChart.tsx @@ -14,7 +14,7 @@ import { PartitionLayout, Settings, } from '@elastic/charts'; -import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; +import styled from 'styled-components'; import { EUI_CHARTS_THEME_DARK, EUI_CHARTS_THEME_LIGHT, @@ -22,6 +22,10 @@ import { import { useUiSetting$ } from '../../../../../../../../src/plugins/kibana_react/public'; import { ChartWrapper } from '../ChartWrapper'; +const StyleChart = styled.div` + height: 100%; +`; + interface Props { options?: Array<{ count: number; @@ -32,65 +36,47 @@ interface Props { export function VisitorBreakdownChart({ options }: Props) { const [darkMode] = useUiSetting$('theme:darkMode'); + const euiChartTheme = darkMode + ? EUI_CHARTS_THEME_DARK + : EUI_CHARTS_THEME_LIGHT; + return ( - - - - d.count as number} - valueGetter="percent" - percentFormatter={(d: number) => - `${Math.round((d + Number.EPSILON) * 100) / 100}%` - } - layers={[ - { - groupByRollup: (d: Datum) => d.name, - nodeLabel: (d: Datum) => d, - // fillLabel: { textInvertible: true }, - shape: { - fillColor: (d) => { - const clrs = [ - euiLightVars.euiColorVis1_behindText, - euiLightVars.euiColorVis0_behindText, - euiLightVars.euiColorVis2_behindText, - euiLightVars.euiColorVis3_behindText, - euiLightVars.euiColorVis4_behindText, - euiLightVars.euiColorVis5_behindText, - euiLightVars.euiColorVis6_behindText, - euiLightVars.euiColorVis7_behindText, - euiLightVars.euiColorVis8_behindText, - euiLightVars.euiColorVis9_behindText, - ]; - return clrs[d.sortIndex]; + + + + + d.count as number} + valueGetter="percent" + percentFormatter={(d: number) => + `${Math.round((d + Number.EPSILON) * 100) / 100}%` + } + layers={[ + { + groupByRollup: (d: Datum) => d.name, + shape: { + fillColor: (d) => + euiChartTheme.theme.colors?.vizColors?.[d.sortIndex]!, }, }, - }, - ]} - config={{ - partitionLayout: PartitionLayout.sunburst, - linkLabel: { - maxCount: 32, - fontSize: 14, - }, - fontFamily: 'Arial', - margin: { top: 0, bottom: 0, left: 0, right: 0 }, - minFontSize: 1, - idealFontSizeJump: 1.1, - outerSizeRatio: 0.9, // - 0.5 * Math.random(), - emptySizeRatio: 0, - circlePadding: 4, - }} - /> - + ]} + config={{ + partitionLayout: PartitionLayout.sunburst, + linkLabel: { maximumSection: Infinity, maxCount: 0 }, + margin: { top: 0, bottom: 0, left: 0, right: 0 }, + outerSizeRatio: 1, // - 0.5 * Math.random(), + circlePadding: 4, + clockwiseSectors: false, + }} + /> + + ); } diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx index 67404ece3d2c..f54a54211359 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/ClientMetrics/index.tsx @@ -22,11 +22,11 @@ const ClFlexGroup = styled(EuiFlexGroup)` export function ClientMetrics() { const { urlParams, uiFilters } = useUrlParams(); - const { start, end, serviceName } = urlParams; + const { start, end } = urlParams; const { data, status } = useFetcher( (callApmApi) => { - if (start && end && serviceName) { + if (start && end) { return callApmApi({ pathname: '/api/apm/rum/client-metrics', params: { @@ -36,7 +36,7 @@ export function ClientMetrics() { } return Promise.resolve(null); }, - [start, end, serviceName, uiFilters] + [start, end, uiFilters] ); const STAT_STYLE = { width: '240px' }; @@ -45,7 +45,7 @@ export function ClientMetrics() { <>{numeral(data?.pageViews?.value).format('0 a') ?? '-'} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/ColorPaletteFlexItem.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/ColorPaletteFlexItem.tsx new file mode 100644 index 000000000000..fc2390acde0b --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/ColorPaletteFlexItem.tsx @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { EuiFlexItem, EuiToolTip } from '@elastic/eui'; +import styled from 'styled-components'; + +const ColoredSpan = styled.div` + height: 16px; + width: 100%; + cursor: pointer; +`; + +const getSpanStyle = ( + position: number, + inFocus: boolean, + hexCode: string, + percentage: number +) => { + let first = position === 0 || percentage === 100; + let last = position === 2 || percentage === 100; + if (percentage === 100) { + first = true; + last = true; + } + + const spanStyle: any = { + backgroundColor: hexCode, + opacity: !inFocus ? 1 : 0.3, + }; + let borderRadius = ''; + + if (first) { + borderRadius = '4px 0 0 4px'; + } + if (last) { + borderRadius = '0 4px 4px 0'; + } + if (first && last) { + borderRadius = '4px'; + } + spanStyle.borderRadius = borderRadius; + + return spanStyle; +}; + +export function ColorPaletteFlexItem({ + hexCode, + inFocus, + percentage, + tooltip, + position, +}: { + hexCode: string; + position: number; + inFocus: boolean; + percentage: number; + tooltip: string; +}) { + const spanStyle = getSpanStyle(position, inFocus, hexCode, percentage); + + return ( + + + + + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/CoreVitalItem.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/CoreVitalItem.tsx new file mode 100644 index 000000000000..a4cbebf20b54 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/CoreVitalItem.tsx @@ -0,0 +1,124 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + EuiFlexGroup, + euiPaletteForStatus, + EuiSpacer, + EuiStat, +} from '@elastic/eui'; +import React, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { PaletteLegends } from './PaletteLegends'; +import { ColorPaletteFlexItem } from './ColorPaletteFlexItem'; +import { + AVERAGE_LABEL, + GOOD_LABEL, + LESS_LABEL, + MORE_LABEL, + POOR_LABEL, +} from './translations'; + +export interface Thresholds { + good: string; + bad: string; +} + +interface Props { + title: string; + value: string; + ranks?: number[]; + loading: boolean; + thresholds: Thresholds; +} + +export function getCoreVitalTooltipMessage( + thresholds: Thresholds, + position: number, + title: string, + percentage: number +) { + const good = position === 0; + const bad = position === 2; + const average = !good && !bad; + + return i18n.translate('xpack.apm.csm.dashboard.webVitals.palette.tooltip', { + defaultMessage: + '{percentage} % of users have {exp} experience because the {title} takes {moreOrLess} than {value}{averageMessage}.', + values: { + percentage, + title: title?.toLowerCase(), + exp: good ? GOOD_LABEL : bad ? POOR_LABEL : AVERAGE_LABEL, + moreOrLess: bad || average ? MORE_LABEL : LESS_LABEL, + value: good || average ? thresholds.good : thresholds.bad, + averageMessage: average + ? i18n.translate('xpack.apm.rum.coreVitals.averageMessage', { + defaultMessage: ' and less than {bad}', + values: { bad: thresholds.bad }, + }) + : '', + }, + }); +} + +export function CoreVitalItem({ + loading, + title, + value, + thresholds, + ranks = [100, 0, 0], +}: Props) { + const palette = euiPaletteForStatus(3); + + const [inFocusInd, setInFocusInd] = useState(null); + + const biggestValIndex = ranks.indexOf(Math.max(...ranks)); + + return ( + <> + + + + {palette.map((hexCode, ind) => ( + + ))} + + + { + setInFocusInd(ind); + }} + /> + + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/PaletteLegends.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/PaletteLegends.tsx new file mode 100644 index 000000000000..84cc5f1ddb23 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/PaletteLegends.tsx @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiHealth, + euiPaletteForStatus, + EuiToolTip, +} from '@elastic/eui'; +import styled from 'styled-components'; +import { getCoreVitalTooltipMessage, Thresholds } from './CoreVitalItem'; + +const PaletteLegend = styled(EuiHealth)` + &:hover { + cursor: pointer; + text-decoration: underline; + background-color: #e7f0f7; + } +`; + +interface Props { + onItemHover: (ind: number | null) => void; + ranks: number[]; + thresholds: Thresholds; + title: string; +} + +export function PaletteLegends({ + ranks, + title, + onItemHover, + thresholds, +}: Props) { + const palette = euiPaletteForStatus(3); + + return ( + + {palette.map((color, ind) => ( + { + onItemHover(ind); + }} + onMouseLeave={() => { + onItemHover(null); + }} + > + + {ranks?.[ind]}% + + + ))} + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/__stories__/CoreVitals.stories.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/__stories__/CoreVitals.stories.tsx new file mode 100644 index 000000000000..a611df00f1e6 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/__stories__/CoreVitals.stories.tsx @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { storiesOf } from '@storybook/react'; +import React from 'react'; +import { EuiThemeProvider } from '../../../../../../../observability/public'; +import { CoreVitalItem } from '../CoreVitalItem'; +import { LCP_LABEL } from '../translations'; + +storiesOf('app/RumDashboard/WebCoreVitals', module) + .addDecorator((storyFn) => {storyFn()}) + .add( + 'Basic', + () => { + return ( + + ); + }, + { + info: { + propTables: false, + source: false, + }, + } + ) + .add( + '50% Good', + () => { + return ( + + ); + }, + { + info: { + propTables: false, + source: false, + }, + } + ) + .add( + '100% Bad', + () => { + return ( + + ); + }, + { + info: { + propTables: false, + source: false, + }, + } + ) + .add( + '100% Average', + () => { + return ( + + ); + }, + { + info: { + propTables: false, + source: false, + }, + } + ); diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/index.tsx new file mode 100644 index 000000000000..e8305a6aef0d --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/index.tsx @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import * as React from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + +import { useFetcher } from '../../../../hooks/useFetcher'; +import { useUrlParams } from '../../../../hooks/useUrlParams'; +import { CLS_LABEL, FID_LABEL, LCP_LABEL } from './translations'; +import { CoreVitalItem } from './CoreVitalItem'; + +const CoreVitalsThresholds = { + LCP: { good: '2.5s', bad: '4.0s' }, + FID: { good: '100ms', bad: '300ms' }, + CLS: { good: '0.1', bad: '0.25' }, +}; + +export function CoreVitals() { + const { urlParams, uiFilters } = useUrlParams(); + + const { start, end, serviceName } = urlParams; + + const { data, status } = useFetcher( + (callApmApi) => { + if (start && end && serviceName) { + return callApmApi({ + pathname: '/api/apm/rum-client/web-core-vitals', + params: { + query: { start, end, uiFilters: JSON.stringify(uiFilters) }, + }, + }); + } + return Promise.resolve(null); + }, + [start, end, serviceName, uiFilters] + ); + + const { lcp, lcpRanks, fid, fidRanks, cls, clsRanks } = data || {}; + + return ( + + + + + + + + + + + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/translations.ts new file mode 100644 index 000000000000..136dfb279e33 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/CoreVitals/translations.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const LCP_LABEL = i18n.translate('xpack.apm.rum.coreVitals.lcp', { + defaultMessage: 'Largest contentful paint', +}); + +export const FID_LABEL = i18n.translate('xpack.apm.rum.coreVitals.fip', { + defaultMessage: 'First input delay', +}); + +export const CLS_LABEL = i18n.translate('xpack.apm.rum.coreVitals.cls', { + defaultMessage: 'Cumulative layout shift', +}); + +export const FCP_LABEL = i18n.translate('xpack.apm.rum.coreVitals.fcp', { + defaultMessage: 'First contentful paint', +}); + +export const TBT_LABEL = i18n.translate('xpack.apm.rum.coreVitals.tbt', { + defaultMessage: 'Total blocking time', +}); + +export const POOR_LABEL = i18n.translate('xpack.apm.rum.coreVitals.poor', { + defaultMessage: 'a poor', +}); + +export const GOOD_LABEL = i18n.translate('xpack.apm.rum.coreVitals.good', { + defaultMessage: 'a good', +}); + +export const AVERAGE_LABEL = i18n.translate( + 'xpack.apm.rum.coreVitals.average', + { + defaultMessage: 'an average', + } +); + +export const MORE_LABEL = i18n.translate('xpack.apm.rum.coreVitals.more', { + defaultMessage: 'more', +}); + +export const LESS_LABEL = i18n.translate('xpack.apm.rum.coreVitals.less', { + defaultMessage: 'less', +}); diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/ResetPercentileZoom.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/ResetPercentileZoom.tsx new file mode 100644 index 000000000000..deaeed70e572 --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/ResetPercentileZoom.tsx @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { + EuiButtonEmpty, + EuiHideFor, + EuiShowFor, + EuiButtonIcon, +} from '@elastic/eui'; +import { I18LABELS } from '../translations'; +import { PercentileRange } from './index'; + +interface Props { + percentileRange: PercentileRange; + setPercentileRange: (value: PercentileRange) => void; +} +export function ResetPercentileZoom({ + percentileRange, + setPercentileRange, +}: Props) { + const isDisabled = + percentileRange.min === null && percentileRange.max === null; + const onClick = () => { + setPercentileRange({ min: null, max: null }); + }; + return ( + <> + + + + + + {I18LABELS.resetZoom} + + + + ); +} diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx index 3e35f1525493..f63b914c7339 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageLoadDistribution/index.tsx @@ -5,19 +5,14 @@ */ import React, { useState } from 'react'; -import { - EuiButtonEmpty, - EuiFlexGroup, - EuiFlexItem, - EuiSpacer, - EuiTitle, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiTitle } from '@elastic/eui'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { useFetcher } from '../../../../hooks/useFetcher'; import { I18LABELS } from '../translations'; import { BreakdownFilter } from '../Breakdowns/BreakdownFilter'; import { PageLoadDistChart } from '../Charts/PageLoadDistChart'; import { BreakdownItem } from '../../../../../typings/ui_filters'; +import { ResetPercentileZoom } from './ResetPercentileZoom'; export interface PercentileRange { min?: number | null; @@ -27,7 +22,7 @@ export interface PercentileRange { export function PageLoadDistribution() { const { urlParams, uiFilters } = useUrlParams(); - const { start, end, serviceName } = urlParams; + const { start, end } = urlParams; const [percentileRange, setPercentileRange] = useState({ min: null, @@ -38,7 +33,7 @@ export function PageLoadDistribution() { const { data, status } = useFetcher( (callApmApi) => { - if (start && end && serviceName) { + if (start && end) { return callApmApi({ pathname: '/api/apm/rum-client/page-load-distribution', params: { @@ -58,14 +53,7 @@ export function PageLoadDistribution() { } return Promise.resolve(null); }, - [ - end, - start, - serviceName, - uiFilters, - percentileRange.min, - percentileRange.max, - ] + [end, start, uiFilters, percentileRange.min, percentileRange.max] ); const onPercentileChange = (min: number, max: number) => { @@ -81,18 +69,10 @@ export function PageLoadDistribution() { - { - setPercentileRange({ min: null, max: null }); - }} - disabled={ - percentileRange.min === null && percentileRange.max === null - } - > - {I18LABELS.resetZoom} - + { const { urlParams, uiFilters } = useUrlParams(); - const { start, end, serviceName } = urlParams; + const { start, end } = urlParams; const { min: minP, max: maxP } = percentileRange ?? {}; return useFetcher( (callApmApi) => { - if (start && end && serviceName && field && value) { + if (start && end && field && value) { return callApmApi({ pathname: '/api/apm/rum-client/page-load-distribution/breakdown', params: { @@ -43,6 +43,6 @@ export const useBreakdowns = ({ percentileRange, field, value }: Props) => { }); } }, - [end, start, serviceName, uiFilters, field, value, minP, maxP] + [end, start, uiFilters, field, value, minP, maxP] ); }; diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx index a67f6dd8e3cb..62ecc4ddbaac 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/PageViewsTrend/index.tsx @@ -16,13 +16,13 @@ import { BreakdownItem } from '../../../../../typings/ui_filters'; export function PageViewsTrend() { const { urlParams, uiFilters } = useUrlParams(); - const { start, end, serviceName } = urlParams; + const { start, end } = urlParams; const [breakdown, setBreakdown] = useState(null); const { data, status } = useFetcher( (callApmApi) => { - if (start && end && serviceName) { + if (start && end) { return callApmApi({ pathname: '/api/apm/rum-client/page-view-trends', params: { @@ -41,7 +41,7 @@ export function PageViewsTrend() { } return Promise.resolve(undefined); }, - [end, start, serviceName, uiFilters, breakdown] + [end, start, uiFilters, breakdown] ); return ( diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx index 24d4470736de..f05c07e8512a 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/RumDashboard.tsx @@ -17,6 +17,7 @@ import { PageViewsTrend } from './PageViewsTrend'; import { PageLoadDistribution } from './PageLoadDistribution'; import { I18LABELS } from './translations'; import { VisitorBreakdown } from './VisitorBreakdown'; +import { CoreVitals } from './CoreVitals'; export function RumDashboard() { return ( @@ -26,7 +27,7 @@ export function RumDashboard() { -

{I18LABELS.pageLoadTimes}

+

{I18LABELS.pageLoadDuration}

@@ -37,13 +38,29 @@ export function RumDashboard() { - - - - + + +

{I18LABELS.coreWebVitals}

+
+ +
+
+ + + + + + + + + + + + + diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdown/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdown/index.tsx index 5c68ebb1667a..e18875f32ff7 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdown/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdown/index.tsx @@ -5,20 +5,20 @@ */ import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiTitle, EuiSpacer } from '@elastic/eui'; import { VisitorBreakdownChart } from '../Charts/VisitorBreakdownChart'; -import { VisitorBreakdownLabel } from '../translations'; +import { I18LABELS, VisitorBreakdownLabel } from '../translations'; import { useFetcher } from '../../../../hooks/useFetcher'; import { useUrlParams } from '../../../../hooks/useUrlParams'; export function VisitorBreakdown() { const { urlParams, uiFilters } = useUrlParams(); - const { start, end, serviceName } = urlParams; + const { start, end } = urlParams; const { data } = useFetcher( (callApmApi) => { - if (start && end && serviceName) { + if (start && end) { return callApmApi({ pathname: '/api/apm/rum-client/visitor-breakdown', params: { @@ -32,32 +32,29 @@ export function VisitorBreakdown() { } return Promise.resolve(null); }, - [end, start, serviceName, uiFilters] + [end, start, uiFilters] ); return ( <> - +

{VisitorBreakdownLabel}

+ - - -

Browser

-
-
- - - -

Operating System

+ +

{I18LABELS.browser}

+ +
- - -

Device

+ +

{I18LABELS.operatingSystem}

+ +
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts index 66eeaf433d2a..660ed5a92a0e 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/translations.ts @@ -25,6 +25,12 @@ export const I18LABELS = { pageLoadTimes: i18n.translate('xpack.apm.rum.dashboard.pageLoadTimes.label', { defaultMessage: 'Page load times', }), + pageLoadDuration: i18n.translate( + 'xpack.apm.rum.dashboard.pageLoadDuration.label', + { + defaultMessage: 'Page load duration', + } + ), pageLoadDistribution: i18n.translate( 'xpack.apm.rum.dashboard.pageLoadDistribution.label', { @@ -46,6 +52,18 @@ export const I18LABELS = { seconds: i18n.translate('xpack.apm.rum.filterGroup.seconds', { defaultMessage: 'seconds', }), + coreWebVitals: i18n.translate('xpack.apm.rum.filterGroup.coreWebVitals', { + defaultMessage: 'Core web vitals', + }), + browser: i18n.translate('xpack.apm.rum.visitorBreakdown.browser', { + defaultMessage: 'Browser', + }), + operatingSystem: i18n.translate( + 'xpack.apm.rum.visitorBreakdown.operatingSystem', + { + defaultMessage: 'Operating system', + } + ), }; export const VisitorBreakdownLabel = i18n.translate( diff --git a/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx index 2f35e329720d..cbb6d9a8fbe4 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx @@ -10,7 +10,6 @@ import React from 'react'; import { isJavaAgentName, isRumAgentName } from '../../../../common/agent_name'; import { useAgentName } from '../../../hooks/useAgentName'; import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; -import { useUrlParams } from '../../../hooks/useUrlParams'; import { EuiTabLink } from '../../shared/EuiTabLink'; import { ErrorOverviewLink } from '../../shared/Links/apm/ErrorOverviewLink'; import { MetricOverviewLink } from '../../shared/Links/apm/MetricOverviewLink'; @@ -24,20 +23,14 @@ import { ServiceNodeOverview } from '../ServiceNodeOverview'; import { TransactionOverview } from '../TransactionOverview'; interface Props { + serviceName: string; tab: 'transactions' | 'errors' | 'metrics' | 'nodes' | 'service-map'; } -export function ServiceDetailTabs({ tab }: Props) { - const { urlParams } = useUrlParams(); - const { serviceName } = urlParams; +export function ServiceDetailTabs({ serviceName, tab }: Props) { const { agentName } = useAgentName(); const { serviceMapEnabled } = useApmPluginContext().config; - if (!serviceName) { - // this never happens, urlParams type is not accurate enough - throw new Error('Service name was not defined'); - } - const transactionsTab = { link: ( @@ -46,7 +39,7 @@ export function ServiceDetailTabs({ tab }: Props) { })} ), - render: () => , + render: () => , name: 'transactions', }; @@ -59,7 +52,7 @@ export function ServiceDetailTabs({ tab }: Props) { ), render: () => { - return ; + return ; }, name: 'errors', }; @@ -75,7 +68,7 @@ export function ServiceDetailTabs({ tab }: Props) { })} ), - render: () => , + render: () => , name: 'nodes', }; tabs.push(nodesListTab); @@ -88,7 +81,9 @@ export function ServiceDetailTabs({ tab }: Props) { })} ), - render: () => , + render: () => ( + + ), name: 'metrics', }; tabs.push(metricsTab); diff --git a/x-pack/plugins/apm/public/components/app/ServiceDetails/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/index.tsx index b5a4ca4799af..67c4a7c4cde1 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceDetails/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceDetails/index.tsx @@ -5,27 +5,26 @@ */ import { + EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiTitle, - EuiButtonEmpty, } from '@elastic/eui'; -import React from 'react'; import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { RouteComponentProps } from 'react-router-dom'; +import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; import { ApmHeader } from '../../shared/ApmHeader'; -import { ServiceDetailTabs } from './ServiceDetailTabs'; -import { useUrlParams } from '../../../hooks/useUrlParams'; import { AlertIntegrations } from './AlertIntegrations'; -import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; +import { ServiceDetailTabs } from './ServiceDetailTabs'; -interface Props { +interface Props extends RouteComponentProps<{ serviceName: string }> { tab: React.ComponentProps['tab']; } -export function ServiceDetails({ tab }: Props) { +export function ServiceDetails({ match, tab }: Props) { const plugin = useApmPluginContext(); - const { urlParams } = useUrlParams(); - const { serviceName } = urlParams; + const { serviceName } = match.params; const capabilities = plugin.core.application.capabilities; const canReadAlerts = !!capabilities.apm['alerting:show']; const canSaveAlerts = !!capabilities.apm['alerting:save']; @@ -76,7 +75,7 @@ export function ServiceDetails({ tab }: Props) {
- + ); } diff --git a/x-pack/plugins/apm/public/components/app/ServiceMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceMetrics/index.tsx index 9b01f9ebb7e9..2fb500f3c991 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceMetrics/index.tsx @@ -21,11 +21,14 @@ import { LocalUIFilters } from '../../shared/LocalUIFilters'; interface ServiceMetricsProps { agentName: string; + serviceName: string; } -export function ServiceMetrics({ agentName }: ServiceMetricsProps) { +export function ServiceMetrics({ + agentName, + serviceName, +}: ServiceMetricsProps) { const { urlParams } = useUrlParams(); - const { serviceName, serviceNodeName } = urlParams; const { data } = useServiceMetricCharts(urlParams, agentName); const { start, end } = urlParams; @@ -34,12 +37,11 @@ export function ServiceMetrics({ agentName }: ServiceMetricsProps) { filterNames: ['host', 'containerId', 'podName', 'serviceVersion'], params: { serviceName, - serviceNodeName, }, projection: Projection.metrics, showCount: false, }), - [serviceName, serviceNodeName] + [serviceName] ); return ( diff --git a/x-pack/plugins/apm/public/components/app/ServiceNodeMetrics/index.test.tsx b/x-pack/plugins/apm/public/components/app/ServiceNodeMetrics/index.test.tsx index eced7457318d..c6f7e68e4f4d 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceNodeMetrics/index.test.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceNodeMetrics/index.test.tsx @@ -8,14 +8,20 @@ import React from 'react'; import { shallow } from 'enzyme'; import { ServiceNodeMetrics } from '.'; import { MockApmPluginContextWrapper } from '../../../context/ApmPluginContext/MockApmPluginContext'; +import { RouteComponentProps } from 'react-router-dom'; describe('ServiceNodeMetrics', () => { describe('render', () => { it('renders', () => { + const props = ({} as unknown) as RouteComponentProps<{ + serviceName: string; + serviceNodeName: string; + }>; + expect(() => shallow( - + ) ).not.toThrowError(); diff --git a/x-pack/plugins/apm/public/components/app/ServiceNodeMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceNodeMetrics/index.tsx index e81968fb298f..84a1920d17fa 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceNodeMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceNodeMetrics/index.tsx @@ -5,30 +5,31 @@ */ import { + EuiCallOut, + EuiFlexGrid, EuiFlexGroup, EuiFlexItem, - EuiTitle, EuiHorizontalRule, - EuiFlexGrid, EuiPanel, EuiSpacer, EuiStat, + EuiTitle, EuiToolTip, - EuiCallOut, } from '@elastic/eui'; -import React from 'react'; import { i18n } from '@kbn/i18n'; -import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n/react'; +import React from 'react'; +import { RouteComponentProps } from 'react-router-dom'; +import styled from 'styled-components'; import { SERVICE_NODE_NAME_MISSING } from '../../../../common/service_nodes'; -import { ApmHeader } from '../../shared/ApmHeader'; -import { useUrlParams } from '../../../hooks/useUrlParams'; +import { ChartsSyncContextProvider } from '../../../context/ChartsSyncContext'; import { useAgentName } from '../../../hooks/useAgentName'; +import { FETCH_STATUS, useFetcher } from '../../../hooks/useFetcher'; import { useServiceMetricCharts } from '../../../hooks/useServiceMetricCharts'; -import { ChartsSyncContextProvider } from '../../../context/ChartsSyncContext'; +import { useUrlParams } from '../../../hooks/useUrlParams'; +import { px, truncate, unit } from '../../../style/variables'; +import { ApmHeader } from '../../shared/ApmHeader'; import { MetricsChart } from '../../shared/charts/MetricsChart'; -import { useFetcher, FETCH_STATUS } from '../../../hooks/useFetcher'; -import { truncate, px, unit } from '../../../style/variables'; import { ElasticDocsLink } from '../../shared/Links/ElasticDocsLink'; const INITIAL_DATA = { @@ -41,17 +42,21 @@ const Truncate = styled.span` ${truncate(px(unit * 12))} `; -export function ServiceNodeMetrics() { - const { urlParams, uiFilters } = useUrlParams(); - const { serviceName, serviceNodeName } = urlParams; +type ServiceNodeMetricsProps = RouteComponentProps<{ + serviceName: string; + serviceNodeName: string; +}>; +export function ServiceNodeMetrics({ match }: ServiceNodeMetricsProps) { + const { urlParams, uiFilters } = useUrlParams(); + const { serviceName, serviceNodeName } = match.params; const { agentName } = useAgentName(); const { data } = useServiceMetricCharts(urlParams, agentName); const { start, end } = urlParams; const { data: { host, containerId } = INITIAL_DATA, status } = useFetcher( (callApmApi) => { - if (serviceName && serviceNodeName && start && end) { + if (start && end) { return callApmApi({ pathname: '/api/apm/services/{serviceName}/node/{serviceNodeName}/metadata', @@ -167,7 +172,7 @@ export function ServiceNodeMetrics() {
)} - {agentName && serviceNodeName && ( + {agentName && ( {data.charts.map((chart) => ( diff --git a/x-pack/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx index 9940a7aabb21..28477d244889 100644 --- a/x-pack/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx @@ -33,9 +33,13 @@ const ServiceNodeName = styled.div` ${truncate(px(8 * unit))} `; -function ServiceNodeOverview() { +interface ServiceNodeOverviewProps { + serviceName: string; +} + +function ServiceNodeOverview({ serviceName }: ServiceNodeOverviewProps) { const { uiFilters, urlParams } = useUrlParams(); - const { serviceName, start, end } = urlParams; + const { start, end } = urlParams; const localFiltersConfig: React.ComponentProps = useMemo( () => ({ @@ -50,7 +54,7 @@ function ServiceNodeOverview() { const { data: items = [] } = useFetcher( (callApmApi) => { - if (!serviceName || !start || !end) { + if (!start || !end) { return undefined; } return callApmApi({ @@ -70,10 +74,6 @@ function ServiceNodeOverview() { [serviceName, start, end, uiFilters] ); - if (!serviceName) { - return null; - } - const columns: Array> = [ { name: ( diff --git a/x-pack/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx b/x-pack/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx index bbaf6340e18f..8d37a8e54d87 100644 --- a/x-pack/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx +++ b/x-pack/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx @@ -5,63 +5,84 @@ */ import { render } from '@testing-library/react'; import { shallow } from 'enzyme'; -import React from 'react'; +import React, { ReactNode } from 'react'; +import { MemoryRouter, RouteComponentProps } from 'react-router-dom'; import { TraceLink } from '../'; +import { ApmPluginContextValue } from '../../../../context/ApmPluginContext'; +import { + mockApmPluginContextValue, + MockApmPluginContextWrapper, +} from '../../../../context/ApmPluginContext/MockApmPluginContext'; import * as hooks from '../../../../hooks/useFetcher'; import * as urlParamsHooks from '../../../../hooks/useUrlParams'; -import { MockApmPluginContextWrapper } from '../../../../context/ApmPluginContext/MockApmPluginContext'; -const renderOptions = { wrapper: MockApmPluginContextWrapper }; +function Wrapper({ children }: { children?: ReactNode }) { + return ( + + + {children} + + + ); +} -jest.mock('../../Main/route_config', () => ({ - routes: [ - { - path: '/services/:serviceName/transactions/view', - name: 'transaction_name', - }, - { - path: '/traces', - name: 'traces', - }, - ], -})); +const renderOptions = { wrapper: Wrapper }; describe('TraceLink', () => { afterAll(() => { jest.clearAllMocks(); }); - it('renders transition page', () => { - const component = render(, renderOptions); + + it('renders a transition page', () => { + const props = ({ + match: { params: { traceId: 'x' } }, + } as unknown) as RouteComponentProps<{ traceId: string }>; + const component = render(, renderOptions); + expect(component.getByText('Fetching trace...')).toBeDefined(); }); - it('renders trace page when transaction is not found', () => { - jest.spyOn(urlParamsHooks, 'useUrlParams').mockReturnValue({ - urlParams: { - traceIdLink: '123', - rangeFrom: 'now-24h', - rangeTo: 'now', - }, - refreshTimeRange: jest.fn(), - uiFilters: {}, - }); - jest.spyOn(hooks, 'useFetcher').mockReturnValue({ - data: { transaction: undefined }, - status: hooks.FETCH_STATUS.SUCCESS, - refetch: jest.fn(), - }); + describe('when no transaction is found', () => { + it('renders a trace page', () => { + jest.spyOn(urlParamsHooks, 'useUrlParams').mockReturnValue({ + urlParams: { + rangeFrom: 'now-24h', + rangeTo: 'now', + }, + refreshTimeRange: jest.fn(), + uiFilters: {}, + }); + jest.spyOn(hooks, 'useFetcher').mockReturnValue({ + data: { transaction: undefined }, + status: hooks.FETCH_STATUS.SUCCESS, + refetch: jest.fn(), + }); + + const props = ({ + match: { params: { traceId: '123' } }, + } as unknown) as RouteComponentProps<{ traceId: string }>; + const component = shallow(); - const component = shallow(); - expect(component.prop('to')).toEqual( - '/traces?kuery=trace.id%2520%253A%2520%2522123%2522&rangeFrom=now-24h&rangeTo=now' - ); + expect(component.prop('to')).toEqual( + '/traces?kuery=trace.id%2520%253A%2520%2522123%2522&rangeFrom=now-24h&rangeTo=now' + ); + }); }); describe('transaction page', () => { beforeAll(() => { jest.spyOn(urlParamsHooks, 'useUrlParams').mockReturnValue({ urlParams: { - traceIdLink: '123', rangeFrom: 'now-24h', rangeTo: 'now', }, @@ -69,6 +90,7 @@ describe('TraceLink', () => { uiFilters: {}, }); }); + it('renders with date range params', () => { const transaction = { service: { name: 'foo' }, @@ -84,7 +106,12 @@ describe('TraceLink', () => { status: hooks.FETCH_STATUS.SUCCESS, refetch: jest.fn(), }); - const component = shallow(); + + const props = ({ + match: { params: { traceId: '123' } }, + } as unknown) as RouteComponentProps<{ traceId: string }>; + const component = shallow(); + expect(component.prop('to')).toEqual( '/services/foo/transactions/view?traceId=123&transactionId=456&transactionName=bar&transactionType=GET&rangeFrom=now-24h&rangeTo=now' ); diff --git a/x-pack/plugins/apm/public/components/app/TraceLink/index.tsx b/x-pack/plugins/apm/public/components/app/TraceLink/index.tsx index 55ab275002b4..584af956c202 100644 --- a/x-pack/plugins/apm/public/components/app/TraceLink/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TraceLink/index.tsx @@ -6,7 +6,7 @@ import { EuiEmptyPrompt } from '@elastic/eui'; import React from 'react'; -import { Redirect } from 'react-router-dom'; +import { Redirect, RouteComponentProps } from 'react-router-dom'; import styled from 'styled-components'; import url from 'url'; import { TRACE_ID } from '../../../../common/elasticsearch_fieldnames'; @@ -58,9 +58,10 @@ const redirectToTracePage = ({ }, }); -export function TraceLink() { +export function TraceLink({ match }: RouteComponentProps<{ traceId: string }>) { + const { traceId } = match.params; const { urlParams } = useUrlParams(); - const { traceIdLink: traceId, rangeFrom, rangeTo } = urlParams; + const { rangeFrom, rangeTo } = urlParams; const { data = { transaction: null }, status } = useFetcher( (callApmApi) => { diff --git a/x-pack/plugins/apm/public/components/app/TransactionDetails/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/index.tsx index 515fcbc88c90..bab31c9a460d 100644 --- a/x-pack/plugins/apm/public/components/app/TransactionDetails/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/index.tsx @@ -13,6 +13,7 @@ import { EuiTitle, } from '@elastic/eui'; import React, { useMemo } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; import { useTrackPageview } from '../../../../../observability/public'; import { Projection } from '../../../../common/projections'; import { ChartsSyncContextProvider } from '../../../context/ChartsSyncContext'; @@ -29,7 +30,10 @@ import { LocalUIFilters } from '../../shared/LocalUIFilters'; import { TransactionDistribution } from './Distribution'; import { WaterfallWithSummmary } from './WaterfallWithSummmary'; -export function TransactionDetails() { +type TransactionDetailsProps = RouteComponentProps<{ serviceName: string }>; + +export function TransactionDetails({ match }: TransactionDetailsProps) { + const { serviceName } = match.params; const location = useLocation(); const { urlParams } = useUrlParams(); const { @@ -41,7 +45,7 @@ export function TransactionDetails() { const { waterfall, exceedsMax, status: waterfallStatus } = useWaterfall( urlParams ); - const { transactionName, transactionType, serviceName } = urlParams; + const { transactionName, transactionType } = urlParams; useTrackPageview({ app: 'apm', path: 'transaction_details' }); useTrackPageview({ app: 'apm', path: 'transaction_details', delay: 15000 }); diff --git a/x-pack/plugins/apm/public/components/app/TransactionOverview/TransactionOverview.test.tsx b/x-pack/plugins/apm/public/components/app/TransactionOverview/TransactionOverview.test.tsx index 81fe9e228266..b7d1b93600a7 100644 --- a/x-pack/plugins/apm/public/components/app/TransactionOverview/TransactionOverview.test.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionOverview/TransactionOverview.test.tsx @@ -12,7 +12,6 @@ import { } from '@testing-library/react'; import { createMemoryHistory } from 'history'; import { CoreStart } from 'kibana/public'; -import { omit } from 'lodash'; import React from 'react'; import { Router } from 'react-router-dom'; import { createKibanaReactContext } from 'src/plugins/kibana_react/public'; @@ -42,7 +41,7 @@ function setup({ }) { const defaultLocation = { pathname: '/services/foo/transactions', - search: fromQuery(omit(urlParams, 'serviceName')), + search: fromQuery(urlParams), } as any; history.replace({ @@ -60,7 +59,7 @@ function setup({ - + @@ -87,9 +86,7 @@ describe('TransactionOverview', () => { it('should redirect to first type', () => { setup({ serviceTransactionTypes: ['firstType', 'secondType'], - urlParams: { - serviceName: 'MyServiceName', - }, + urlParams: {}, }); expect(history.replace).toHaveBeenCalledWith( expect.objectContaining({ @@ -107,7 +104,6 @@ describe('TransactionOverview', () => { serviceTransactionTypes: ['firstType', 'secondType'], urlParams: { transactionType: 'secondType', - serviceName: 'MyServiceName', }, }); @@ -122,7 +118,6 @@ describe('TransactionOverview', () => { serviceTransactionTypes: ['firstType', 'secondType'], urlParams: { transactionType: 'secondType', - serviceName: 'MyServiceName', }, }); @@ -143,7 +138,6 @@ describe('TransactionOverview', () => { serviceTransactionTypes: ['firstType'], urlParams: { transactionType: 'firstType', - serviceName: 'MyServiceName', }, }); diff --git a/x-pack/plugins/apm/public/components/app/TransactionOverview/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionOverview/index.tsx index 5999988abe84..544e2450fe5d 100644 --- a/x-pack/plugins/apm/public/components/app/TransactionOverview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionOverview/index.tsx @@ -59,11 +59,14 @@ function getRedirectLocation({ } } -export function TransactionOverview() { +interface TransactionOverviewProps { + serviceName: string; +} + +export function TransactionOverview({ serviceName }: TransactionOverviewProps) { const location = useLocation(); const { urlParams } = useUrlParams(); - - const { serviceName, transactionType } = urlParams; + const { transactionType } = urlParams; // TODO: fetching of transaction types should perhaps be lifted since it is needed in several places. Context? const serviceTransactionTypes = useServiceTransactionTypes(urlParams); diff --git a/x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx b/x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx index 9a61e773d73b..7e5c789507e0 100644 --- a/x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx @@ -8,7 +8,7 @@ import { EuiSelect } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { History } from 'history'; import React from 'react'; -import { useHistory } from 'react-router-dom'; +import { useHistory, useParams } from 'react-router-dom'; import { ENVIRONMENT_ALL, ENVIRONMENT_NOT_DEFINED, @@ -63,10 +63,11 @@ function getOptions(environments: string[]) { export function EnvironmentFilter() { const history = useHistory(); const location = useLocation(); + const { serviceName } = useParams<{ serviceName?: string }>(); const { uiFilters, urlParams } = useUrlParams(); const { environment } = uiFilters; - const { serviceName, start, end } = urlParams; + const { start, end } = urlParams; const { environments, status = 'loading' } = useEnvironments({ serviceName, start, diff --git a/x-pack/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.tsx b/x-pack/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.tsx index 734483979595..7b284696477f 100644 --- a/x-pack/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.tsx @@ -3,21 +3,21 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; -import { EuiFieldNumber } from '@elastic/eui'; +import { EuiFieldNumber, EuiSelect } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { isFinite } from 'lodash'; -import { EuiSelect } from '@elastic/eui'; +import React from 'react'; +import { useParams } from 'react-router-dom'; import { ForLastExpression } from '../../../../../triggers_actions_ui/public'; import { ALERT_TYPES_CONFIG } from '../../../../common/alert_types'; -import { ServiceAlertTrigger } from '../ServiceAlertTrigger'; -import { PopoverExpression } from '../ServiceAlertTrigger/PopoverExpression'; -import { useEnvironments } from '../../../hooks/useEnvironments'; -import { useUrlParams } from '../../../hooks/useUrlParams'; import { ENVIRONMENT_ALL, getEnvironmentLabel, } from '../../../../common/environment_filter_values'; +import { useEnvironments } from '../../../hooks/useEnvironments'; +import { useUrlParams } from '../../../hooks/useUrlParams'; +import { ServiceAlertTrigger } from '../ServiceAlertTrigger'; +import { PopoverExpression } from '../ServiceAlertTrigger/PopoverExpression'; export interface ErrorRateAlertTriggerParams { windowSize: number; @@ -34,9 +34,9 @@ interface Props { export function ErrorRateAlertTrigger(props: Props) { const { setAlertParams, setAlertProperty, alertParams } = props; - + const { serviceName } = useParams<{ serviceName?: string }>(); const { urlParams } = useUrlParams(); - const { serviceName, start, end } = urlParams; + const { start, end } = urlParams; const { environmentOptions } = useEnvironments({ serviceName, start, end }); const defaults = { diff --git a/x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts b/x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts index 5bac01cfaf55..74d7ace20dae 100644 --- a/x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts +++ b/x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts @@ -4,18 +4,29 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESFilter } from '../../../../typings/elasticsearch'; import { - TRANSACTION_TYPE, ERROR_GROUP_ID, PROCESSOR_EVENT, - TRANSACTION_NAME, SERVICE_NAME, + TRANSACTION_NAME, + TRANSACTION_TYPE, } from '../../../../common/elasticsearch_fieldnames'; +import { UIProcessorEvent } from '../../../../common/processor_event'; +import { ESFilter } from '../../../../typings/elasticsearch'; import { IUrlParams } from '../../../context/UrlParamsContext/types'; -export function getBoolFilter(urlParams: IUrlParams) { - const { start, end, serviceName, processorEvent } = urlParams; +export function getBoolFilter({ + groupId, + processorEvent, + serviceName, + urlParams, +}: { + groupId?: string; + processorEvent?: UIProcessorEvent; + serviceName?: string; + urlParams: IUrlParams; +}) { + const { start, end } = urlParams; if (!start || !end) { throw new Error('Date range was not defined'); @@ -63,9 +74,9 @@ export function getBoolFilter(urlParams: IUrlParams) { term: { [PROCESSOR_EVENT]: 'error' }, }); - if (urlParams.errorGroupId) { + if (groupId) { boolFilter.push({ - term: { [ERROR_GROUP_ID]: urlParams.errorGroupId }, + term: { [ERROR_GROUP_ID]: groupId }, }); } break; diff --git a/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx b/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx index a52676ee8959..efd1446f21b2 100644 --- a/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import { startsWith, uniqueId } from 'lodash'; import React, { useState } from 'react'; -import { useHistory } from 'react-router-dom'; +import { useHistory, useParams } from 'react-router-dom'; import styled from 'styled-components'; import { esKuery, @@ -22,6 +22,7 @@ import { fromQuery, toQuery } from '../Links/url_helpers'; import { getBoolFilter } from './get_bool_filter'; // @ts-expect-error import { Typeahead } from './Typeahead'; +import { useProcessorEvent } from './use_processor_event'; const Container = styled.div` margin-bottom: 10px; @@ -38,6 +39,10 @@ function convertKueryToEsQuery(kuery: string, indexPattern: IIndexPattern) { } export function KueryBar() { + const { groupId, serviceName } = useParams<{ + groupId?: string; + serviceName?: string; + }>(); const history = useHistory(); const [state, setState] = useState({ suggestions: [], @@ -49,7 +54,7 @@ export function KueryBar() { let currentRequestCheck; - const { processorEvent } = urlParams; + const processorEvent = useProcessorEvent(); const examples = { transaction: 'transaction.duration.us > 300000', @@ -98,7 +103,12 @@ export function KueryBar() { (await data.autocomplete.getQuerySuggestions({ language: 'kuery', indexPatterns: [indexPattern], - boolFilter: getBoolFilter(urlParams), + boolFilter: getBoolFilter({ + groupId, + processorEvent, + serviceName, + urlParams, + }), query: inputValue, selectionStart, selectionEnd: selectionStart, diff --git a/x-pack/plugins/apm/public/components/shared/KueryBar/use_processor_event.ts b/x-pack/plugins/apm/public/components/shared/KueryBar/use_processor_event.ts new file mode 100644 index 000000000000..1e8686f0fe5e --- /dev/null +++ b/x-pack/plugins/apm/public/components/shared/KueryBar/use_processor_event.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useLocation } from 'react-router-dom'; +import { + ProcessorEvent, + UIProcessorEvent, +} from '../../../../common/processor_event'; + +/** + * Infer the processor.event to used based on the route path + */ +export function useProcessorEvent(): UIProcessorEvent | undefined { + const { pathname } = useLocation(); + const paths = pathname.split('/').slice(1); + const pageName = paths[0]; + + switch (pageName) { + case 'services': + let servicePageName = paths[2]; + + if (servicePageName === 'nodes' && paths.length > 3) { + servicePageName = 'metrics'; + } + + switch (servicePageName) { + case 'transactions': + return ProcessorEvent.transaction; + case 'errors': + return ProcessorEvent.error; + case 'metrics': + return ProcessorEvent.metric; + case 'nodes': + return ProcessorEvent.metric; + + default: + return undefined; + } + case 'traces': + return ProcessorEvent.transaction; + default: + return undefined; + } +} diff --git a/x-pack/plugins/apm/public/components/shared/ServiceAlertTrigger/index.tsx b/x-pack/plugins/apm/public/components/shared/ServiceAlertTrigger/index.tsx index 6d90a10891c2..86dc7f5a9047 100644 --- a/x-pack/plugins/apm/public/components/shared/ServiceAlertTrigger/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/ServiceAlertTrigger/index.tsx @@ -6,7 +6,7 @@ import React, { useEffect } from 'react'; import { EuiSpacer, EuiFlexGrid, EuiFlexItem } from '@elastic/eui'; -import { useUrlParams } from '../../../hooks/useUrlParams'; +import { useParams } from 'react-router-dom'; interface Props { alertTypeName: string; @@ -17,7 +17,7 @@ interface Props { } export function ServiceAlertTrigger(props: Props) { - const { urlParams } = useUrlParams(); + const { serviceName } = useParams<{ serviceName?: string }>(); const { fields, @@ -29,7 +29,7 @@ export function ServiceAlertTrigger(props: Props) { const params: Record = { ...defaults, - serviceName: urlParams.serviceName!, + serviceName, }; useEffect(() => { diff --git a/x-pack/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.tsx b/x-pack/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.tsx index ba12b11c9527..3c1669c39ac4 100644 --- a/x-pack/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.tsx @@ -40,12 +40,12 @@ interface Props { export function TransactionDurationAlertTrigger(props: Props) { const { setAlertParams, alertParams, setAlertProperty } = props; - + const { serviceName } = alertParams; const { urlParams } = useUrlParams(); const transactionTypes = useServiceTransactionTypes(urlParams); - const { serviceName, start, end } = urlParams; + const { start, end } = urlParams; const { environmentOptions } = useEnvironments({ serviceName, start, end }); if (!transactionTypes.length) { diff --git a/x-pack/plugins/apm/public/components/shared/TransactionDurationAnomalyAlertTrigger/index.tsx b/x-pack/plugins/apm/public/components/shared/TransactionDurationAnomalyAlertTrigger/index.tsx index 911c51013a84..20e0a3f27c4a 100644 --- a/x-pack/plugins/apm/public/components/shared/TransactionDurationAnomalyAlertTrigger/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionDurationAnomalyAlertTrigger/index.tsx @@ -42,9 +42,10 @@ interface Props { export function TransactionDurationAnomalyAlertTrigger(props: Props) { const { setAlertParams, alertParams, setAlertProperty } = props; + const { serviceName } = alertParams; const { urlParams } = useUrlParams(); const transactionTypes = useServiceTransactionTypes(urlParams); - const { serviceName, start, end } = urlParams; + const { start, end } = urlParams; const { environmentOptions } = useEnvironments({ serviceName, start, end }); const supportedTransactionTypes = transactionTypes.filter((transactionType) => [TRANSACTION_PAGE_LOAD, TRANSACTION_REQUEST].includes(transactionType) diff --git a/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/ml_header.tsx b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/ml_header.tsx index f829b5841efa..52b0470d3155 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/ml_header.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/ml_header.tsx @@ -4,13 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiIconTip } from '@elastic/eui'; +import { EuiFlexItem, EuiIconTip, EuiText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { isEmpty } from 'lodash'; import React from 'react'; -import { EuiFlexItem } from '@elastic/eui'; +import { useParams } from 'react-router-dom'; import styled from 'styled-components'; -import { i18n } from '@kbn/i18n'; -import { EuiText } from '@elastic/eui'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { MLJobLink } from '../../Links/MachineLearningLinks/MLJobLink'; @@ -32,16 +31,14 @@ const ShiftedEuiText = styled(EuiText)` `; export function MLHeader({ hasValidMlLicense, mlJobId }: Props) { + const { serviceName } = useParams<{ serviceName?: string }>(); const { urlParams } = useUrlParams(); if (!hasValidMlLicense || !mlJobId) { return null; } - const { serviceName, kuery, transactionType } = urlParams; - if (!serviceName) { - return null; - } + const { kuery, transactionType } = urlParams; const hasKuery = !isEmpty(kuery); const icon = hasKuery ? ( diff --git a/x-pack/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx b/x-pack/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx index 8334efffbd51..48206572932b 100644 --- a/x-pack/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx +++ b/x-pack/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx @@ -39,6 +39,7 @@ const mockCore = { apm: {}, }, currentAppId$: new Observable(), + navigateToUrl: (url: string) => {}, }, chrome: { docTitle: { change: () => {} }, diff --git a/x-pack/plugins/apm/public/context/ChartsSyncContext.tsx b/x-pack/plugins/apm/public/context/ChartsSyncContext.tsx index 801c1d7e53f2..7df35bc44322 100644 --- a/x-pack/plugins/apm/public/context/ChartsSyncContext.tsx +++ b/x-pack/plugins/apm/public/context/ChartsSyncContext.tsx @@ -5,7 +5,7 @@ */ import React, { ReactNode, useMemo, useState } from 'react'; -import { useHistory } from 'react-router-dom'; +import { useHistory, useParams } from 'react-router-dom'; import { fromQuery, toQuery } from '../components/shared/Links/url_helpers'; import { useFetcher } from '../hooks/useFetcher'; import { useUrlParams } from '../hooks/useUrlParams'; @@ -20,9 +20,10 @@ const ChartsSyncContext = React.createContext<{ function ChartsSyncContextProvider({ children }: { children: ReactNode }) { const history = useHistory(); const [time, setTime] = useState(null); + const { serviceName } = useParams<{ serviceName?: string }>(); const { urlParams, uiFilters } = useUrlParams(); - const { start, end, serviceName } = urlParams; + const { start, end } = urlParams; const { environment } = uiFilters; const { data = { annotations: [] } } = useFetcher( diff --git a/x-pack/plugins/apm/public/context/UrlParamsContext/__tests__/UrlParamsContext.test.tsx b/x-pack/plugins/apm/public/context/UrlParamsContext/__tests__/UrlParamsContext.test.tsx index fbb79eae6a13..9989e568953f 100644 --- a/x-pack/plugins/apm/public/context/UrlParamsContext/__tests__/UrlParamsContext.test.tsx +++ b/x-pack/plugins/apm/public/context/UrlParamsContext/__tests__/UrlParamsContext.test.tsx @@ -41,24 +41,6 @@ describe('UrlParamsContext', () => { moment.tz.setDefault(''); }); - it('should have default params', () => { - const location = { - pathname: '/services/opbeans-node/transactions', - } as Location; - - jest - .spyOn(Date, 'now') - .mockImplementation(() => new Date('2000-06-15T12:00:00Z').getTime()); - const wrapper = mountParams(location); - const params = getDataFromOutput(wrapper); - - expect(params).toEqual({ - serviceName: 'opbeans-node', - page: 0, - processorEvent: 'transaction', - }); - }); - it('should read values in from location', () => { const location = { pathname: '/test/pathname', diff --git a/x-pack/plugins/apm/public/context/UrlParamsContext/helpers.ts b/x-pack/plugins/apm/public/context/UrlParamsContext/helpers.ts index 65514ff71d02..45db4dcc94cc 100644 --- a/x-pack/plugins/apm/public/context/UrlParamsContext/helpers.ts +++ b/x-pack/plugins/apm/public/context/UrlParamsContext/helpers.ts @@ -7,18 +7,6 @@ import { compact, pickBy } from 'lodash'; import datemath from '@elastic/datemath'; import { IUrlParams } from './types'; -import { - ProcessorEvent, - UIProcessorEvent, -} from '../../../common/processor_event'; - -interface PathParams { - processorEvent?: UIProcessorEvent; - serviceName?: string; - errorGroupId?: string; - serviceNodeName?: string; - traceId?: string; -} export function getParsedDate(rawDate?: string, opts = {}) { if (rawDate) { @@ -67,68 +55,3 @@ export function getPathAsArray(pathname: string = '') { export function removeUndefinedProps(obj: T): Partial { return pickBy(obj, (value) => value !== undefined); } - -export function getPathParams(pathname: string = ''): PathParams { - const paths = getPathAsArray(pathname); - const pageName = paths[0]; - // TODO: use react router's real match params instead of guessing the path order - - switch (pageName) { - case 'services': - let servicePageName = paths[2]; - const serviceName = paths[1]; - const serviceNodeName = paths[3]; - - if (servicePageName === 'nodes' && paths.length > 3) { - servicePageName = 'metrics'; - } - - switch (servicePageName) { - case 'transactions': - return { - processorEvent: ProcessorEvent.transaction, - serviceName, - }; - case 'errors': - return { - processorEvent: ProcessorEvent.error, - serviceName, - errorGroupId: paths[3], - }; - case 'metrics': - return { - processorEvent: ProcessorEvent.metric, - serviceName, - serviceNodeName, - }; - case 'nodes': - return { - processorEvent: ProcessorEvent.metric, - serviceName, - }; - case 'service-map': - return { - serviceName, - }; - default: - return {}; - } - - case 'traces': - return { - processorEvent: ProcessorEvent.transaction, - }; - case 'link-to': - const link = paths[1]; - switch (link) { - case 'trace': - return { - traceId: paths[2], - }; - default: - return {}; - } - default: - return {}; - } -} diff --git a/x-pack/plugins/apm/public/context/UrlParamsContext/resolveUrlParams.ts b/x-pack/plugins/apm/public/context/UrlParamsContext/resolveUrlParams.ts index 2201e162904a..8feb4ac1858d 100644 --- a/x-pack/plugins/apm/public/context/UrlParamsContext/resolveUrlParams.ts +++ b/x-pack/plugins/apm/public/context/UrlParamsContext/resolveUrlParams.ts @@ -7,7 +7,6 @@ import { Location } from 'history'; import { IUrlParams } from './types'; import { - getPathParams, removeUndefinedProps, getStart, getEnd, @@ -26,14 +25,6 @@ type TimeUrlParams = Pick< >; export function resolveUrlParams(location: Location, state: TimeUrlParams) { - const { - processorEvent, - serviceName, - serviceNodeName, - errorGroupId, - traceId: traceIdLink, - } = getPathParams(location.pathname); - const query = toQuery(location.search); const { @@ -85,15 +76,6 @@ export function resolveUrlParams(location: Location, state: TimeUrlParams) { transactionType, searchTerm: toString(searchTerm), - // path params - processorEvent, - serviceName, - traceIdLink, - errorGroupId, - serviceNodeName: serviceNodeName - ? decodeURIComponent(serviceNodeName) - : serviceNodeName, - // ui filters environment, ...localUIFilters, diff --git a/x-pack/plugins/apm/public/context/UrlParamsContext/types.ts b/x-pack/plugins/apm/public/context/UrlParamsContext/types.ts index 7b50a705afa3..574eca3b74f7 100644 --- a/x-pack/plugins/apm/public/context/UrlParamsContext/types.ts +++ b/x-pack/plugins/apm/public/context/UrlParamsContext/types.ts @@ -6,12 +6,10 @@ // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { LocalUIFilterName } from '../../../server/lib/ui_filters/local_ui_filters/config'; -import { UIProcessorEvent } from '../../../common/processor_event'; export type IUrlParams = { detailTab?: string; end?: string; - errorGroupId?: string; flyoutDetailTab?: string; kuery?: string; environment?: string; @@ -19,7 +17,6 @@ export type IUrlParams = { rangeTo?: string; refreshInterval?: number; refreshPaused?: boolean; - serviceName?: string; sortDirection?: string; sortField?: string; start?: string; @@ -30,8 +27,5 @@ export type IUrlParams = { waterfallItemId?: string; page?: number; pageSize?: number; - serviceNodeName?: string; searchTerm?: string; - processorEvent?: UIProcessorEvent; - traceIdLink?: string; } & Partial>; diff --git a/x-pack/plugins/apm/public/hooks/useAgentName.ts b/x-pack/plugins/apm/public/hooks/useAgentName.ts index 7a11b662f06f..1f8a3b916ecd 100644 --- a/x-pack/plugins/apm/public/hooks/useAgentName.ts +++ b/x-pack/plugins/apm/public/hooks/useAgentName.ts @@ -3,13 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import { useParams } from 'react-router-dom'; import { useFetcher } from './useFetcher'; import { useUrlParams } from './useUrlParams'; export function useAgentName() { + const { serviceName } = useParams<{ serviceName?: string }>(); const { urlParams } = useUrlParams(); - const { start, end, serviceName } = urlParams; + const { start, end } = urlParams; const { data: agentName, error, status } = useFetcher( (callApmApi) => { diff --git a/x-pack/plugins/apm/public/hooks/useServiceMetricCharts.ts b/x-pack/plugins/apm/public/hooks/useServiceMetricCharts.ts index 78f022ec6b8b..f4a981ff0975 100644 --- a/x-pack/plugins/apm/public/hooks/useServiceMetricCharts.ts +++ b/x-pack/plugins/apm/public/hooks/useServiceMetricCharts.ts @@ -4,10 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ +import { useParams } from 'react-router-dom'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { MetricsChartsByAgentAPIResponse } from '../../server/lib/metrics/get_metrics_chart_data_by_agent'; -import { IUrlParams } from '../context/UrlParamsContext/types'; import { useUiFilters } from '../context/UrlParamsContext'; +import { IUrlParams } from '../context/UrlParamsContext/types'; import { useFetcher } from './useFetcher'; const INITIAL_DATA: MetricsChartsByAgentAPIResponse = { @@ -18,7 +19,8 @@ export function useServiceMetricCharts( urlParams: IUrlParams, agentName?: string ) { - const { serviceName, start, end, serviceNodeName } = urlParams; + const { serviceName } = useParams<{ serviceName?: string }>(); + const { start, end } = urlParams; const uiFilters = useUiFilters(urlParams); const { data = INITIAL_DATA, error, status } = useFetcher( (callApmApi) => { @@ -31,14 +33,13 @@ export function useServiceMetricCharts( start, end, agentName, - serviceNodeName, uiFilters: JSON.stringify(uiFilters), }, }, }); } }, - [serviceName, start, end, agentName, serviceNodeName, uiFilters] + [serviceName, start, end, agentName, uiFilters] ); return { diff --git a/x-pack/plugins/apm/public/hooks/useServiceTransactionTypes.tsx b/x-pack/plugins/apm/public/hooks/useServiceTransactionTypes.tsx index 227cd849d6c7..4e110ac2d438 100644 --- a/x-pack/plugins/apm/public/hooks/useServiceTransactionTypes.tsx +++ b/x-pack/plugins/apm/public/hooks/useServiceTransactionTypes.tsx @@ -4,13 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ +import { useParams } from 'react-router-dom'; import { IUrlParams } from '../context/UrlParamsContext/types'; import { useFetcher } from './useFetcher'; const INITIAL_DATA = { transactionTypes: [] }; export function useServiceTransactionTypes(urlParams: IUrlParams) { - const { serviceName, start, end } = urlParams; + const { serviceName } = useParams<{ serviceName?: string }>(); + const { start, end } = urlParams; const { data = INITIAL_DATA } = useFetcher( (callApmApi) => { if (serviceName && start && end) { diff --git a/x-pack/plugins/apm/public/hooks/useTransactionList.ts b/x-pack/plugins/apm/public/hooks/useTransactionList.ts index 0ad221b95b4f..9c3a18b9c0d0 100644 --- a/x-pack/plugins/apm/public/hooks/useTransactionList.ts +++ b/x-pack/plugins/apm/public/hooks/useTransactionList.ts @@ -4,10 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IUrlParams } from '../context/UrlParamsContext/types'; +import { useParams } from 'react-router-dom'; import { useUiFilters } from '../context/UrlParamsContext'; -import { useFetcher } from './useFetcher'; +import { IUrlParams } from '../context/UrlParamsContext/types'; import { APIReturnType } from '../services/rest/createCallApmApi'; +import { useFetcher } from './useFetcher'; type TransactionsAPIResponse = APIReturnType< '/api/apm/services/{serviceName}/transaction_groups' @@ -20,7 +21,8 @@ const DEFAULT_RESPONSE: TransactionsAPIResponse = { }; export function useTransactionList(urlParams: IUrlParams) { - const { serviceName, transactionType, start, end } = urlParams; + const { serviceName } = useParams<{ serviceName?: string }>(); + const { transactionType, start, end } = urlParams; const uiFilters = useUiFilters(urlParams); const { data = DEFAULT_RESPONSE, error, status } = useFetcher( (callApmApi) => { diff --git a/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx b/x-pack/plugins/apm/public/hooks/use_breadcrumbs.test.tsx similarity index 65% rename from x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx rename to x-pack/plugins/apm/public/hooks/use_breadcrumbs.test.tsx index 102a3d91e4a9..dcd6ed0ba493 100644 --- a/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx +++ b/x-pack/plugins/apm/public/hooks/use_breadcrumbs.test.tsx @@ -4,63 +4,56 @@ * you may not use this file except in compliance with the Elastic License. */ -import { mount } from 'enzyme'; -import React from 'react'; +import { renderHook } from '@testing-library/react-hooks'; +import produce from 'immer'; +import React, { ReactNode } from 'react'; import { MemoryRouter } from 'react-router-dom'; -import { ApmPluginContextValue } from '../../../context/ApmPluginContext'; -import { routes } from './route_config'; -import { UpdateBreadcrumbs } from './UpdateBreadcrumbs'; +import { routes } from '../components/app/Main/route_config'; +import { ApmPluginContextValue } from '../context/ApmPluginContext'; import { - MockApmPluginContextWrapper, mockApmPluginContextValue, -} from '../../../context/ApmPluginContext/MockApmPluginContext'; + MockApmPluginContextWrapper, +} from '../context/ApmPluginContext/MockApmPluginContext'; +import { useBreadcrumbs } from './use_breadcrumbs'; -const setBreadcrumbs = jest.fn(); -const changeTitle = jest.fn(); +function createWrapper(path: string) { + return ({ children }: { children?: ReactNode }) => { + const value = (produce(mockApmPluginContextValue, (draft) => { + draft.core.application.navigateToUrl = (url: string) => Promise.resolve(); + draft.core.chrome.docTitle.change = changeTitle; + draft.core.chrome.setBreadcrumbs = setBreadcrumbs; + }) as unknown) as ApmPluginContextValue; -function mountBreadcrumb(route: string, params = '') { - mount( - - - + return ( + + + {children} + - - ); - expect(setBreadcrumbs).toHaveBeenCalledTimes(1); + ); + }; } -describe('UpdateBreadcrumbs', () => { - beforeEach(() => { - setBreadcrumbs.mockReset(); - changeTitle.mockReset(); - }); +function mountBreadcrumb(path: string) { + renderHook(() => useBreadcrumbs(routes), { wrapper: createWrapper(path) }); +} - it('Changes the homepage title', () => { +const changeTitle = jest.fn(); +const setBreadcrumbs = jest.fn(); + +describe('useBreadcrumbs', () => { + it('changes the page title', () => { mountBreadcrumb('/'); + expect(changeTitle).toHaveBeenCalledWith(['APM']); }); - it('/services/:serviceName/errors/:groupId', () => { + test('/services/:serviceName/errors/:groupId', () => { mountBreadcrumb( - '/services/opbeans-node/errors/myGroupId', - 'rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0' + '/services/opbeans-node/errors/myGroupId?kuery=myKuery&rangeFrom=now-24h&rangeTo=now&refreshPaused=true&refreshInterval=0' ); - const breadcrumbs = setBreadcrumbs.mock.calls[0][0]; - expect(breadcrumbs).toEqual( + + expect(setBreadcrumbs).toHaveBeenCalledWith( expect.arrayContaining([ expect.objectContaining({ text: 'APM', @@ -95,10 +88,10 @@ describe('UpdateBreadcrumbs', () => { ]); }); - it('/services/:serviceName/errors', () => { - mountBreadcrumb('/services/opbeans-node/errors'); - const breadcrumbs = setBreadcrumbs.mock.calls[0][0]; - expect(breadcrumbs).toEqual( + test('/services/:serviceName/errors', () => { + mountBreadcrumb('/services/opbeans-node/errors?kuery=myKuery'); + + expect(setBreadcrumbs).toHaveBeenCalledWith( expect.arrayContaining([ expect.objectContaining({ text: 'APM', @@ -115,6 +108,7 @@ describe('UpdateBreadcrumbs', () => { expect.objectContaining({ text: 'Errors', href: undefined }), ]) ); + expect(changeTitle).toHaveBeenCalledWith([ 'Errors', 'opbeans-node', @@ -123,10 +117,10 @@ describe('UpdateBreadcrumbs', () => { ]); }); - it('/services/:serviceName/transactions', () => { - mountBreadcrumb('/services/opbeans-node/transactions'); - const breadcrumbs = setBreadcrumbs.mock.calls[0][0]; - expect(breadcrumbs).toEqual( + test('/services/:serviceName/transactions', () => { + mountBreadcrumb('/services/opbeans-node/transactions?kuery=myKuery'); + + expect(setBreadcrumbs).toHaveBeenCalledWith( expect.arrayContaining([ expect.objectContaining({ text: 'APM', @@ -152,14 +146,12 @@ describe('UpdateBreadcrumbs', () => { ]); }); - it('/services/:serviceName/transactions/view?transactionName=my-transaction-name', () => { + test('/services/:serviceName/transactions/view?transactionName=my-transaction-name', () => { mountBreadcrumb( - '/services/opbeans-node/transactions/view', - 'transactionName=my-transaction-name' + '/services/opbeans-node/transactions/view?kuery=myKuery&transactionName=my-transaction-name' ); - const breadcrumbs = setBreadcrumbs.mock.calls[0][0]; - expect(breadcrumbs).toEqual( + expect(setBreadcrumbs).toHaveBeenCalledWith( expect.arrayContaining([ expect.objectContaining({ text: 'APM', diff --git a/x-pack/plugins/apm/public/hooks/use_breadcrumbs.ts b/x-pack/plugins/apm/public/hooks/use_breadcrumbs.ts new file mode 100644 index 000000000000..640170bf3bff --- /dev/null +++ b/x-pack/plugins/apm/public/hooks/use_breadcrumbs.ts @@ -0,0 +1,214 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { History, Location } from 'history'; +import { ChromeBreadcrumb } from 'kibana/public'; +import { MouseEvent, ReactNode, useEffect } from 'react'; +import { + matchPath, + RouteComponentProps, + useHistory, + match as Match, + useLocation, +} from 'react-router-dom'; +import { APMRouteDefinition, BreadcrumbTitle } from '../application/routes'; +import { getAPMHref } from '../components/shared/Links/apm/APMLink'; +import { useApmPluginContext } from './useApmPluginContext'; + +interface BreadcrumbWithoutLink extends ChromeBreadcrumb { + match: Match>; +} + +interface BreadcrumbFunctionArgs extends RouteComponentProps { + breadcrumbTitle: BreadcrumbTitle; +} + +/** + * Call the breadcrumb function if there is one, otherwise return it as a string + */ +function getBreadcrumbText({ + breadcrumbTitle, + history, + location, + match, +}: BreadcrumbFunctionArgs) { + return typeof breadcrumbTitle === 'function' + ? breadcrumbTitle({ history, location, match }) + : breadcrumbTitle; +} + +/** + * Get a breadcrumb from the current path and route definitions. + */ +function getBreadcrumb({ + currentPath, + history, + location, + routes, +}: { + currentPath: string; + history: History; + location: Location; + routes: APMRouteDefinition[]; +}) { + return routes.reduce( + (found, { breadcrumb, ...routeDefinition }) => { + if (found) { + return found; + } + + if (!breadcrumb) { + return null; + } + + const match = matchPath>( + currentPath, + routeDefinition + ); + + if (match) { + return { + match, + text: getBreadcrumbText({ + breadcrumbTitle: breadcrumb, + history, + location, + match, + }), + }; + } + + return null; + }, + null + ); +} + +/** + * Once we have the breadcrumbs, we need to iterate through the list again to + * add the href and onClick, since we need to know which one is the final + * breadcrumb + */ +function addLinksToBreadcrumbs({ + breadcrumbs, + navigateToUrl, + wrappedGetAPMHref, +}: { + breadcrumbs: BreadcrumbWithoutLink[]; + navigateToUrl: (url: string) => Promise; + wrappedGetAPMHref: (path: string) => string; +}) { + return breadcrumbs.map((breadcrumb, index) => { + const isLastBreadcrumbItem = index === breadcrumbs.length - 1; + + // Make the link not clickable if it's the last item + const href = isLastBreadcrumbItem + ? undefined + : wrappedGetAPMHref(breadcrumb.match.url); + const onClick = !href + ? undefined + : (event: MouseEvent) => { + event.preventDefault(); + navigateToUrl(href); + }; + + return { + ...breadcrumb, + match: undefined, + href, + onClick, + }; + }); +} + +/** + * Convert a list of route definitions to a list of breadcrumbs + */ +function routeDefinitionsToBreadcrumbs({ + history, + location, + routes, +}: { + history: History; + location: Location; + routes: APMRouteDefinition[]; +}) { + const breadcrumbs: BreadcrumbWithoutLink[] = []; + const { pathname } = location; + + pathname + .split('?')[0] + .replace(/\/$/, '') + .split('/') + .reduce((acc, next) => { + // `/1/2/3` results in match checks for `/1`, `/1/2`, `/1/2/3`. + const currentPath = !next ? '/' : `${acc}/${next}`; + const breadcrumb = getBreadcrumb({ + currentPath, + history, + location, + routes, + }); + + if (breadcrumb) { + breadcrumbs.push(breadcrumb); + } + + return currentPath === '/' ? '' : currentPath; + }, ''); + + return breadcrumbs; +} + +/** + * Get an array for a page title from a list of breadcrumbs + */ +function getTitleFromBreadcrumbs(breadcrumbs: ChromeBreadcrumb[]): string[] { + function removeNonStrings(item: ReactNode): item is string { + return typeof item === 'string'; + } + + return breadcrumbs + .map(({ text }) => text) + .reverse() + .filter(removeNonStrings); +} + +/** + * Determine the breadcrumbs from the routes, set them, and update the page + * title when the route changes. + */ +export function useBreadcrumbs(routes: APMRouteDefinition[]) { + const history = useHistory(); + const location = useLocation(); + const { search } = location; + const { core } = useApmPluginContext(); + const { basePath } = core.http; + const { navigateToUrl } = core.application; + const { docTitle, setBreadcrumbs } = core.chrome; + const changeTitle = docTitle.change; + + function wrappedGetAPMHref(path: string) { + return getAPMHref({ basePath, path, search }); + } + + const breadcrumbsWithoutLinks = routeDefinitionsToBreadcrumbs({ + history, + location, + routes, + }); + const breadcrumbs = addLinksToBreadcrumbs({ + breadcrumbs: breadcrumbsWithoutLinks, + wrappedGetAPMHref, + navigateToUrl, + }); + const title = getTitleFromBreadcrumbs(breadcrumbs); + + useEffect(() => { + changeTitle(title); + setBreadcrumbs(breadcrumbs); + }, [breadcrumbs, changeTitle, location, title, setBreadcrumbs]); +} diff --git a/x-pack/plugins/apm/readme.md b/x-pack/plugins/apm/readme.md index 9b02972d3530..d6fdb5f52291 100644 --- a/x-pack/plugins/apm/readme.md +++ b/x-pack/plugins/apm/readme.md @@ -162,4 +162,5 @@ You can access the development environment at http://localhost:9001. - [Cypress integration tests](./e2e/README.md) - [VSCode setup instructions](./dev_docs/vscode_setup.md) - [Github PR commands](./dev_docs/github_commands.md) +- [Routing and Linking](./dev_docs/routing_and_linking.md) - [Telemetry](./dev_docs/telemetry.md) diff --git a/x-pack/plugins/apm/scripts/aggregate-latency-metrics/index.ts b/x-pack/plugins/apm/scripts/aggregate-latency-metrics/index.ts index c3cf363cbec0..ef8511291871 100644 --- a/x-pack/plugins/apm/scripts/aggregate-latency-metrics/index.ts +++ b/x-pack/plugins/apm/scripts/aggregate-latency-metrics/index.ts @@ -4,15 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Client } from '@elastic/elasticsearch'; import { argv } from 'yargs'; import pLimit from 'p-limit'; import pRetry from 'p-retry'; -import { parse, format } from 'url'; import { set } from '@elastic/safer-lodash-set'; import { uniq, without, merge, flatten } from 'lodash'; import * as histogram from 'hdr-histogram-js'; -import { ESSearchResponse } from '../../typings/elasticsearch'; import { HOST_NAME, SERVICE_NAME, @@ -28,6 +25,8 @@ import { } from '../../common/elasticsearch_fieldnames'; import { stampLogger } from '../shared/stamp-logger'; import { createOrUpdateIndex } from '../shared/create-or-update-index'; +import { parseIndexUrl } from '../shared/parse_index_url'; +import { ESClient, getEsClient } from '../shared/get_es_client'; // This script will try to estimate how many latency metric documents // will be created based on the available transaction documents. @@ -125,41 +124,18 @@ export async function aggregateLatencyMetrics() { const source = String(argv.source ?? ''); const dest = String(argv.dest ?? ''); - function getClientOptionsFromIndexUrl( - url: string - ): { node: string; index: string } { - const parsed = parse(url); - const { pathname, ...rest } = parsed; + const sourceOptions = parseIndexUrl(source); - return { - node: format(rest), - index: pathname!.replace('/', ''), - }; - } - - const sourceOptions = getClientOptionsFromIndexUrl(source); - - const sourceClient = new Client({ - node: sourceOptions.node, - ssl: { - rejectUnauthorized: false, - }, - requestTimeout: 120000, - }); + const sourceClient = getEsClient({ node: sourceOptions.node }); - let destClient: Client | undefined; + let destClient: ESClient | undefined; let destOptions: { node: string; index: string } | undefined; const uploadMetrics = !!dest; if (uploadMetrics) { - destOptions = getClientOptionsFromIndexUrl(dest); - destClient = new Client({ - node: destOptions.node, - ssl: { - rejectUnauthorized: false, - }, - }); + destOptions = parseIndexUrl(dest); + destClient = getEsClient({ node: destOptions.node }); const mappings = ( await sourceClient.indices.getMapping({ @@ -298,10 +274,9 @@ export async function aggregateLatencyMetrics() { }, }; - const response = (await sourceClient.search(params)) - .body as ESSearchResponse; + const response = await sourceClient.search(params); - const { aggregations } = response; + const { aggregations } = response.body; if (!aggregations) { return buckets; @@ -333,10 +308,9 @@ export async function aggregateLatencyMetrics() { }, }; - const response = (await sourceClient.search(params)) - .body as ESSearchResponse; + const response = await sourceClient.search(params); - return response.hits.total.value; + return response.body.hits.total.value; } const [buckets, numberOfTransactionDocuments] = await Promise.all([ diff --git a/x-pack/plugins/apm/scripts/create-functional-tests-archive.js b/x-pack/plugins/apm/scripts/create-functional-tests-archive.js new file mode 100644 index 000000000000..6b3473dc2ac0 --- /dev/null +++ b/x-pack/plugins/apm/scripts/create-functional-tests-archive.js @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +// compile typescript on the fly +// eslint-disable-next-line import/no-extraneous-dependencies +require('@babel/register')({ + extensions: ['.js', '.ts'], + plugins: ['@babel/plugin-proposal-optional-chaining'], + presets: [ + '@babel/typescript', + ['@babel/preset-env', { targets: { node: 'current' } }], + ], +}); + +require('./create-functional-tests-archive/index.ts'); diff --git a/x-pack/plugins/apm/scripts/create-functional-tests-archive/index.ts b/x-pack/plugins/apm/scripts/create-functional-tests-archive/index.ts new file mode 100644 index 000000000000..723ff03dc499 --- /dev/null +++ b/x-pack/plugins/apm/scripts/create-functional-tests-archive/index.ts @@ -0,0 +1,143 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { argv } from 'yargs'; +import { execSync } from 'child_process'; +import moment from 'moment'; +import path from 'path'; +import fs from 'fs'; +import { stampLogger } from '../shared/stamp-logger'; + +async function run() { + stampLogger(); + + const archiveName = 'apm_8.0.0'; + + // include important APM data and ML data + const indices = + 'apm-*-transaction,apm-*-span,apm-*-error,apm-*-metric,.ml-anomalies*,.ml-config'; + + const esUrl = argv['es-url'] as string | undefined; + + if (!esUrl) { + throw new Error('--es-url is not set'); + } + const kibanaUrl = argv['kibana-url'] as string | undefined; + + if (!kibanaUrl) { + throw new Error('--kibana-url is not set'); + } + const gte = moment().subtract(1, 'hour').toISOString(); + const lt = moment(gte).add(30, 'minutes').toISOString(); + + // eslint-disable-next-line no-console + console.log(`Archiving from ${gte} to ${lt}...`); + + // APM data uses '@timestamp' (ECS), ML data uses 'timestamp' + + const rangeQueries = [ + { + range: { + '@timestamp': { + gte, + lt, + }, + }, + }, + { + range: { + timestamp: { + gte, + lt, + }, + }, + }, + ]; + + // some of the data is timeless/content + const query = { + bool: { + should: [ + ...rangeQueries, + { + bool: { + must_not: [ + { + exists: { + field: '@timestamp', + }, + }, + { + exists: { + field: 'timestamp', + }, + }, + ], + }, + }, + ], + minimum_should_match: 1, + }, + }; + + const root = path.join(__dirname, '../../../../..'); + const commonDir = path.join(root, 'x-pack/test/apm_api_integration/common'); + const archivesDir = path.join(commonDir, 'fixtures/es_archiver'); + + // create the archive + + execSync( + `node scripts/es_archiver save ${archiveName} ${indices} --dir=${archivesDir} --kibana-url=${kibanaUrl} --es-url=${esUrl} --query='${JSON.stringify( + query + )}'`, + { + cwd: root, + stdio: 'inherit', + } + ); + + const currentConfig = {}; + + // get the current metadata and extend/override metadata for the new archive + const configFilePath = path.join(commonDir, 'archives_metadata.ts'); + + try { + Object.assign(currentConfig, (await import(configFilePath)).default); + } catch (error) { + // do nothing + } + + const newConfig = { + ...currentConfig, + [archiveName]: { + start: gte, + end: lt, + }, + }; + + fs.writeFileSync( + configFilePath, + `export default ${JSON.stringify(newConfig, null, 2)}`, + { encoding: 'utf-8' } + ); + + // run ESLint on the generated metadata files + + execSync('node scripts/eslint **/*/archives_metadata.ts --fix', { + cwd: root, + stdio: 'inherit', + }); +} + +run() + .then(() => { + process.exit(0); + }) + .catch((err) => { + // eslint-disable-next-line no-console + console.log(err); + process.exit(1); + }); diff --git a/x-pack/plugins/apm/scripts/shared/create-or-update-index.ts b/x-pack/plugins/apm/scripts/shared/create-or-update-index.ts index 6d44e12fb00a..01fa5b0509bc 100644 --- a/x-pack/plugins/apm/scripts/shared/create-or-update-index.ts +++ b/x-pack/plugins/apm/scripts/shared/create-or-update-index.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Client } from '@elastic/elasticsearch'; +import { ESClient } from './get_es_client'; export async function createOrUpdateIndex({ client, @@ -12,7 +12,7 @@ export async function createOrUpdateIndex({ indexName, template, }: { - client: Client; + client: ESClient; clear: boolean; indexName: string; template: any; diff --git a/x-pack/plugins/apm/scripts/shared/get_es_client.ts b/x-pack/plugins/apm/scripts/shared/get_es_client.ts new file mode 100644 index 000000000000..86dfd92190fd --- /dev/null +++ b/x-pack/plugins/apm/scripts/shared/get_es_client.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Client } from '@elastic/elasticsearch'; +import { ApiKeyAuth, BasicAuth } from '@elastic/elasticsearch/lib/pool'; +import { ESSearchResponse, ESSearchRequest } from '../../typings/elasticsearch'; + +export type ESClient = ReturnType; + +export function getEsClient({ + node, + auth, +}: { + node: string; + auth?: BasicAuth | ApiKeyAuth; +}) { + const client = new Client({ + node, + ssl: { + rejectUnauthorized: false, + }, + requestTimeout: 120000, + auth, + }); + + return { + ...client, + async search( + request: TSearchRequest + ) { + const response = await client.search(request as any); + + return { + ...response, + body: response.body as ESSearchResponse, + }; + }, + }; +} diff --git a/x-pack/plugins/apm/scripts/shared/parse_index_url.ts b/x-pack/plugins/apm/scripts/shared/parse_index_url.ts new file mode 100644 index 000000000000..190f7fda396b --- /dev/null +++ b/x-pack/plugins/apm/scripts/shared/parse_index_url.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { parse, format } from 'url'; + +export function parseIndexUrl(url: string): { node: string; index: string } { + const parsed = parse(url); + const { pathname, ...rest } = parsed; + + return { + node: format(rest), + index: pathname!.replace('/', ''), + }; +} diff --git a/x-pack/plugins/apm/server/lib/rum_client/get_web_core_vitals.ts b/x-pack/plugins/apm/server/lib/rum_client/get_web_core_vitals.ts new file mode 100644 index 000000000000..9395e5fe1433 --- /dev/null +++ b/x-pack/plugins/apm/server/lib/rum_client/get_web_core_vitals.ts @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { getRumOverviewProjection } from '../../projections/rum_overview'; +import { mergeProjection } from '../../projections/util/merge_projection'; +import { + Setup, + SetupTimeRange, + SetupUIFilters, +} from '../helpers/setup_request'; +import { + CLS_FIELD, + FID_FIELD, + LCP_FIELD, +} from '../../../common/elasticsearch_fieldnames'; + +export async function getWebCoreVitals({ + setup, +}: { + setup: Setup & SetupTimeRange & SetupUIFilters; +}) { + const projection = getRumOverviewProjection({ + setup, + }); + + const params = mergeProjection(projection, { + body: { + size: 0, + query: { + bool: { + filter: [ + ...projection.body.query.bool.filter, + { + term: { + 'user_agent.name': 'Chrome', + }, + }, + ], + }, + }, + aggs: { + lcp: { + percentiles: { + field: LCP_FIELD, + percents: [50], + }, + }, + fid: { + percentiles: { + field: FID_FIELD, + percents: [50], + }, + }, + cls: { + percentiles: { + field: CLS_FIELD, + percents: [50], + }, + }, + lcpRanks: { + percentile_ranks: { + field: LCP_FIELD, + values: [2500, 4000], + keyed: false, + }, + }, + fidRanks: { + percentile_ranks: { + field: FID_FIELD, + values: [100, 300], + keyed: false, + }, + }, + clsRanks: { + percentile_ranks: { + field: CLS_FIELD, + values: [0.1, 0.25], + keyed: false, + }, + }, + }, + }, + }); + + const { apmEventClient } = setup; + + const response = await apmEventClient.search(params); + const { + lcp, + cls, + fid, + lcpRanks, + fidRanks, + clsRanks, + } = response.aggregations!; + + const getRanksPercentages = ( + ranks: Array<{ key: number; value: number }> + ) => { + const ranksVal = (ranks ?? [0, 0]).map( + ({ value }) => value?.toFixed(0) ?? 0 + ); + return [ + Number(ranksVal?.[0]), + Number(ranksVal?.[1]) - Number(ranksVal?.[0]), + 100 - Number(ranksVal?.[1]), + ]; + }; + + // Divide by 1000 to convert ms into seconds + return { + cls: String(cls.values['50.0'] || 0), + fid: ((fid.values['50.0'] || 0) / 1000).toFixed(2), + lcp: ((lcp.values['50.0'] || 0) / 1000).toFixed(2), + + lcpRanks: getRanksPercentages(lcpRanks.values), + fidRanks: getRanksPercentages(fidRanks.values), + clsRanks: getRanksPercentages(clsRanks.values), + }; +} diff --git a/x-pack/plugins/apm/server/lib/settings/apm_indices/get_apm_indices.ts b/x-pack/plugins/apm/server/lib/settings/apm_indices/get_apm_indices.ts index 2f3b2a602048..926b2025f425 100644 --- a/x-pack/plugins/apm/server/lib/settings/apm_indices/get_apm_indices.ts +++ b/x-pack/plugins/apm/server/lib/settings/apm_indices/get_apm_indices.ts @@ -5,7 +5,7 @@ */ import { merge } from 'lodash'; -import { Server } from 'hapi'; + import { SavedObjectsClient } from 'src/core/server'; import { PromiseReturnType } from '../../../../../observability/typings/common'; import { @@ -32,10 +32,6 @@ export interface ApmIndicesConfig { export type ApmIndicesName = keyof ApmIndicesConfig; -export type ScopedSavedObjectsClient = ReturnType< - Server['savedObjects']['getScopedSavedObjectsClient'] ->; - async function getApmIndicesSavedObject( savedObjectsClient: ISavedObjectsClient ) { diff --git a/x-pack/plugins/apm/server/routes/create_apm_api.ts b/x-pack/plugins/apm/server/routes/create_apm_api.ts index 5dff13e5b37e..cf7a02cde975 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_api.ts +++ b/x-pack/plugins/apm/server/routes/create_apm_api.ts @@ -77,6 +77,7 @@ import { rumPageLoadDistBreakdownRoute, rumServicesRoute, rumVisitorsBreakdownRoute, + rumWebCoreVitals, } from './rum_client'; import { observabilityOverviewHasDataRoute, @@ -172,6 +173,7 @@ const createApmApi = () => { .add(rumClientMetricsRoute) .add(rumServicesRoute) .add(rumVisitorsBreakdownRoute) + .add(rumWebCoreVitals) // Observability dashboard .add(observabilityOverviewHasDataRoute) diff --git a/x-pack/plugins/apm/server/routes/rum_client.ts b/x-pack/plugins/apm/server/routes/rum_client.ts index 0781512c6f7a..e17791f56eef 100644 --- a/x-pack/plugins/apm/server/routes/rum_client.ts +++ b/x-pack/plugins/apm/server/routes/rum_client.ts @@ -14,6 +14,7 @@ import { getPageLoadDistribution } from '../lib/rum_client/get_page_load_distrib import { getPageLoadDistBreakdown } from '../lib/rum_client/get_pl_dist_breakdown'; import { getRumServices } from '../lib/rum_client/get_rum_services'; import { getVisitorBreakdown } from '../lib/rum_client/get_visitor_breakdown'; +import { getWebCoreVitals } from '../lib/rum_client/get_web_core_vitals'; export const percentileRangeRt = t.partial({ minPercentile: t.string, @@ -117,3 +118,15 @@ export const rumVisitorsBreakdownRoute = createRoute(() => ({ return getVisitorBreakdown({ setup }); }, })); + +export const rumWebCoreVitals = createRoute(() => ({ + path: '/api/apm/rum-client/web-core-vitals', + params: { + query: t.intersection([uiFiltersRt, rangeRt]), + }, + handler: async ({ context, request }) => { + const setup = await setupRequest(context, request); + + return getWebCoreVitals({ setup }); + }, +})); diff --git a/x-pack/plugins/apm/server/routes/typings.ts b/x-pack/plugins/apm/server/routes/typings.ts index 97013273c9bc..78c820fbf4ec 100644 --- a/x-pack/plugins/apm/server/routes/typings.ts +++ b/x-pack/plugins/apm/server/routes/typings.ts @@ -13,7 +13,6 @@ import { } from 'src/core/server'; import { PickByValue, Optional } from 'utility-types'; import { Observable } from 'rxjs'; -import { Server } from 'hapi'; import { ObservabilityPluginSetup } from '../../../observability/server'; import { SecurityPluginSetup } from '../../../security/server'; import { MlPluginSetup } from '../../../ml/server'; @@ -57,12 +56,6 @@ export interface Route< }) => Promise; } -export type APMLegacyServer = Pick & { - plugins: { - elasticsearch: Server['plugins']['elasticsearch']; - }; -}; - export type APMRequestHandlerContext< TDecodedParams extends { [key in keyof Params]: any } = {} > = RequestHandlerContext & { diff --git a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts index f95761412254..7a7592b24896 100644 --- a/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts +++ b/x-pack/plugins/apm/typings/elasticsearch/aggregations.ts @@ -146,7 +146,7 @@ export interface AggregationOptionsByType { buckets: number; } & AggregationSourceOptions; percentile_ranks: { - values: string[]; + values: Array; keyed?: boolean; hdr?: { number_of_significant_value_digits: number }; } & AggregationSourceOptions; diff --git a/x-pack/plugins/case/common/constants.ts b/x-pack/plugins/case/common/constants.ts index bd12c258a538..15a318002390 100644 --- a/x-pack/plugins/case/common/constants.ts +++ b/x-pack/plugins/case/common/constants.ts @@ -28,5 +28,11 @@ export const CASE_USER_ACTIONS_URL = `${CASE_DETAILS_URL}/user_actions`; export const ACTION_URL = '/api/actions'; export const ACTION_TYPES_URL = '/api/actions/list_action_types'; export const SERVICENOW_ACTION_TYPE_ID = '.servicenow'; +export const JIRA_ACTION_TYPE_ID = '.jira'; +export const RESILIENT_ACTION_TYPE_ID = '.resilient'; -export const SUPPORTED_CONNECTORS = ['.servicenow', '.jira', '.resilient']; +export const SUPPORTED_CONNECTORS = [ + SERVICENOW_ACTION_TYPE_ID, + JIRA_ACTION_TYPE_ID, + RESILIENT_ACTION_TYPE_ID, +]; diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts b/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts index 28e75dd2f8c3..a22d7ae5cea2 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts @@ -12,6 +12,7 @@ import { CASE_CONFIGURE_CONNECTORS_URL, SUPPORTED_CONNECTORS, SERVICENOW_ACTION_TYPE_ID, + JIRA_ACTION_TYPE_ID, } from '../../../../../common/constants'; /* @@ -36,8 +37,9 @@ export function initCaseConfigureGetActionConnector({ caseService, router }: Rou (action) => SUPPORTED_CONNECTORS.includes(action.actionTypeId) && // Need this filtering temporary to display only Case owned ServiceNow connectors - (action.actionTypeId !== SERVICENOW_ACTION_TYPE_ID || - (action.actionTypeId === SERVICENOW_ACTION_TYPE_ID && action.config!.isCaseOwned)) + (![SERVICENOW_ACTION_TYPE_ID, JIRA_ACTION_TYPE_ID].includes(action.actionTypeId) || + ([SERVICENOW_ACTION_TYPE_ID, JIRA_ACTION_TYPE_ID].includes(action.actionTypeId) && + action.config?.isCaseOwned === true)) ); return response.ok({ body: results }); } catch (error) { diff --git a/x-pack/plugins/data_enhanced/common/index.ts b/x-pack/plugins/data_enhanced/common/index.ts index d6a3c73aaf36..012f1204da46 100644 --- a/x-pack/plugins/data_enhanced/common/index.ts +++ b/x-pack/plugins/data_enhanced/common/index.ts @@ -5,7 +5,6 @@ */ export { - EnhancedSearchParams, IEnhancedEsSearchRequest, IAsyncSearchRequest, ENHANCED_ES_SEARCH_STRATEGY, diff --git a/x-pack/plugins/data_enhanced/common/search/index.ts b/x-pack/plugins/data_enhanced/common/search/index.ts index 2ae422bd6b7d..696938a403e8 100644 --- a/x-pack/plugins/data_enhanced/common/search/index.ts +++ b/x-pack/plugins/data_enhanced/common/search/index.ts @@ -5,7 +5,6 @@ */ export { - EnhancedSearchParams, IEnhancedEsSearchRequest, IAsyncSearchRequest, ENHANCED_ES_SEARCH_STRATEGY, diff --git a/x-pack/plugins/data_enhanced/common/search/types.ts b/x-pack/plugins/data_enhanced/common/search/types.ts index 0d3d3a69e1e5..24d459ade4bf 100644 --- a/x-pack/plugins/data_enhanced/common/search/types.ts +++ b/x-pack/plugins/data_enhanced/common/search/types.ts @@ -4,21 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IEsSearchRequest, ISearchRequestParams } from '../../../../../src/plugins/data/common'; +import { IEsSearchRequest } from '../../../../../src/plugins/data/common'; export const ENHANCED_ES_SEARCH_STRATEGY = 'ese'; -export interface EnhancedSearchParams extends ISearchRequestParams { - ignoreThrottled: boolean; -} - export interface IAsyncSearchRequest extends IEsSearchRequest { /** * The ID received from the response from the initial request */ id?: string; - - params?: EnhancedSearchParams; } export interface IEnhancedEsSearchRequest extends IEsSearchRequest { diff --git a/x-pack/plugins/data_enhanced/public/plugin.ts b/x-pack/plugins/data_enhanced/public/plugin.ts index 7f6e3feac067..ccc93316482c 100644 --- a/x-pack/plugins/data_enhanced/public/plugin.ts +++ b/x-pack/plugins/data_enhanced/public/plugin.ts @@ -23,6 +23,8 @@ export type DataEnhancedStart = ReturnType; export class DataEnhancedPlugin implements Plugin { + private enhancedSearchInterceptor!: EnhancedSearchInterceptor; + public setup( core: CoreSetup, { data }: DataEnhancedSetupDependencies @@ -32,20 +34,17 @@ export class DataEnhancedPlugin setupKqlQuerySuggestionProvider(core) ); - const enhancedSearchInterceptor = new EnhancedSearchInterceptor( - { - toasts: core.notifications.toasts, - http: core.http, - uiSettings: core.uiSettings, - startServices: core.getStartServices(), - usageCollector: data.search.usageCollector, - }, - core.injectedMetadata.getInjectedVar('esRequestTimeout') as number - ); + this.enhancedSearchInterceptor = new EnhancedSearchInterceptor({ + toasts: core.notifications.toasts, + http: core.http, + uiSettings: core.uiSettings, + startServices: core.getStartServices(), + usageCollector: data.search.usageCollector, + }); data.__enhance({ search: { - searchInterceptor: enhancedSearchInterceptor, + searchInterceptor: this.enhancedSearchInterceptor, }, }); } @@ -53,4 +52,8 @@ export class DataEnhancedPlugin public start(core: CoreStart, plugins: DataEnhancedStartDependencies) { setAutocompleteService(plugins.data.autocomplete); } + + public stop() { + this.enhancedSearchInterceptor.stop(); + } } diff --git a/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts b/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts index 1e2c7987b704..261e03887acd 100644 --- a/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts +++ b/x-pack/plugins/data_enhanced/public/search/search_interceptor.test.ts @@ -7,7 +7,7 @@ import { coreMock } from '../../../../../src/core/public/mocks'; import { EnhancedSearchInterceptor } from './search_interceptor'; import { CoreSetup, CoreStart } from 'kibana/public'; -import { AbortError } from '../../../../../src/plugins/data/common'; +import { AbortError, UI_SETTINGS } from '../../../../../src/plugins/data/common'; const timeTravel = (msToRun = 0) => { jest.advanceTimersByTime(msToRun); @@ -43,6 +43,15 @@ describe('EnhancedSearchInterceptor', () => { mockCoreSetup = coreMock.createSetup(); mockCoreStart = coreMock.createStart(); + mockCoreSetup.uiSettings.get.mockImplementation((name: string) => { + switch (name) { + case UI_SETTINGS.SEARCH_TIMEOUT: + return 1000; + default: + return; + } + }); + next.mockClear(); error.mockClear(); complete.mockClear(); @@ -64,16 +73,13 @@ describe('EnhancedSearchInterceptor', () => { ]); }); - searchInterceptor = new EnhancedSearchInterceptor( - { - toasts: mockCoreSetup.notifications.toasts, - startServices: mockPromise as any, - http: mockCoreSetup.http, - uiSettings: mockCoreSetup.uiSettings, - usageCollector: mockUsageCollector, - }, - 1000 - ); + searchInterceptor = new EnhancedSearchInterceptor({ + toasts: mockCoreSetup.notifications.toasts, + startServices: mockPromise as any, + http: mockCoreSetup.http, + uiSettings: mockCoreSetup.uiSettings, + usageCollector: mockUsageCollector, + }); }); describe('search', () => { diff --git a/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts b/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts index 6f7899d1188b..61cf579d3136 100644 --- a/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts +++ b/x-pack/plugins/data_enhanced/public/search/search_interceptor.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { throwError, EMPTY, timer, from } from 'rxjs'; +import { throwError, EMPTY, timer, from, Subscription } from 'rxjs'; import { mergeMap, expand, takeUntil, finalize, tap } from 'rxjs/operators'; import { getLongQueryNotification } from './long_query_notification'; import { @@ -17,14 +17,25 @@ import { IAsyncSearchOptions } from '.'; import { IAsyncSearchRequest, ENHANCED_ES_SEARCH_STRATEGY } from '../../common'; export class EnhancedSearchInterceptor extends SearchInterceptor { + private uiSettingsSub: Subscription; + private searchTimeout: number; + /** - * This class should be instantiated with a `requestTimeout` corresponding with how many ms after - * requests are initiated that they should automatically cancel. - * @param deps `SearchInterceptorDeps` - * @param requestTimeout Usually config value `elasticsearch.requestTimeout` + * @internal */ - constructor(deps: SearchInterceptorDeps, requestTimeout?: number) { - super(deps, requestTimeout); + constructor(deps: SearchInterceptorDeps) { + super(deps); + this.searchTimeout = deps.uiSettings.get(UI_SETTINGS.SEARCH_TIMEOUT); + + this.uiSettingsSub = deps.uiSettings + .get$(UI_SETTINGS.SEARCH_TIMEOUT) + .subscribe((timeout: number) => { + this.searchTimeout = timeout; + }); + } + + public stop() { + this.uiSettingsSub.unsubscribe(); } /** @@ -69,12 +80,10 @@ export class EnhancedSearchInterceptor extends SearchInterceptor { ) { let { id } = request; - request.params = { - ignoreThrottled: !this.deps.uiSettings.get(UI_SETTINGS.SEARCH_INCLUDE_FROZEN), - ...request.params, - }; - - const { combinedSignal, cleanup } = this.setupTimers(options); + const { combinedSignal, cleanup } = this.setupAbortSignal({ + abortSignal: options.abortSignal, + timeout: this.searchTimeout, + }); const aborted$ = from(toPromise(combinedSignal)); const strategy = options?.strategy || ENHANCED_ES_SEARCH_STRATEGY; @@ -108,7 +117,7 @@ export class EnhancedSearchInterceptor extends SearchInterceptor { // we don't need to send a follow-up request to delete this search. Otherwise, we // send the follow-up request to delete this search, then throw an abort error. if (id !== undefined) { - this.deps.http.delete(`/internal/search/es/${id}`); + this.deps.http.delete(`/internal/search/${strategy}/${id}`); } }, }), diff --git a/x-pack/plugins/data_enhanced/server/plugin.ts b/x-pack/plugins/data_enhanced/server/plugin.ts index f9b6fd4e9ad6..3b05e83d208b 100644 --- a/x-pack/plugins/data_enhanced/server/plugin.ts +++ b/x-pack/plugins/data_enhanced/server/plugin.ts @@ -19,6 +19,7 @@ import { import { enhancedEsSearchStrategyProvider } from './search'; import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/server'; import { ENHANCED_ES_SEARCH_STRATEGY } from '../common'; +import { getUiSettings } from './ui_settings'; interface SetupDependencies { data: DataPluginSetup; @@ -35,6 +36,8 @@ export class EnhancedDataServerPlugin implements Plugin, deps: SetupDependencies) { const usage = deps.usageCollection ? usageProvider(core) : undefined; + core.uiSettings.register(getUiSettings()); + deps.data.search.registerSearchStrategy( ENHANCED_ES_SEARCH_STRATEGY, enhancedEsSearchStrategyProvider( diff --git a/x-pack/plugins/data_enhanced/server/search/es_search_strategy.test.ts b/x-pack/plugins/data_enhanced/server/search/es_search_strategy.test.ts index a287f72ca916..f4f3d894a457 100644 --- a/x-pack/plugins/data_enhanced/server/search/es_search_strategy.test.ts +++ b/x-pack/plugins/data_enhanced/server/search/es_search_strategy.test.ts @@ -5,8 +5,8 @@ */ import { RequestHandlerContext } from '../../../../../src/core/server'; -import { pluginInitializerContextConfigMock } from '../../../../../src/core/server/mocks'; import { enhancedEsSearchStrategyProvider } from './es_search_strategy'; +import { BehaviorSubject } from 'rxjs'; const mockAsyncResponse = { body: { @@ -42,6 +42,11 @@ describe('ES search strategy', () => { }; const mockContext = { core: { + uiSettings: { + client: { + get: jest.fn(), + }, + }, elasticsearch: { client: { asCurrentUser: { @@ -55,7 +60,15 @@ describe('ES search strategy', () => { }, }, }; - const mockConfig$ = pluginInitializerContextConfigMock({}).legacy.globalConfig$; + const mockConfig$ = new BehaviorSubject({ + elasticsearch: { + shardTimeout: { + asMilliseconds: () => { + return 100; + }, + }, + }, + }); beforeEach(() => { mockApiCaller.mockClear(); diff --git a/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts b/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts index 4ace1c4c5385..eda6178dc8e5 100644 --- a/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts +++ b/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts @@ -5,23 +5,19 @@ */ import { first } from 'rxjs/operators'; -import { mapKeys, snakeCase } from 'lodash'; -import { Observable } from 'rxjs'; import { SearchResponse } from 'elasticsearch'; +import { Observable } from 'rxjs'; +import { SharedGlobalConfig, RequestHandlerContext, Logger } from '../../../../../src/core/server'; import { - SharedGlobalConfig, - RequestHandlerContext, - ElasticsearchClient, - Logger, -} from '../../../../../src/core/server'; -import { - getDefaultSearchParams, getTotalLoaded, ISearchStrategy, SearchUsage, + getDefaultSearchParams, + getShardTimeout, + toSnakeCase, + shimHitsTotal, } from '../../../../../src/plugins/data/server'; import { IEnhancedEsSearchRequest } from '../../common'; -import { shimHitsTotal } from './shim_hits_total'; import { ISearchOptions, IEsSearchResponse } from '../../../../../src/plugins/data/common/search'; function isEnhancedEsSearchResponse(response: any): response is IEsSearchResponse { @@ -39,17 +35,13 @@ export const enhancedEsSearchStrategyProvider = ( options?: ISearchOptions ) => { logger.debug(`search ${JSON.stringify(request.params) || request.id}`); - const config = await config$.pipe(first()).toPromise(); - const client = context.core.elasticsearch.client.asCurrentUser; - const defaultParams = getDefaultSearchParams(config); - const params = { ...defaultParams, ...request.params }; const isAsync = request.indexType !== 'rollup'; try { const response = isAsync - ? await asyncSearch(client, { ...request, params }, options) - : await rollupSearch(client, { ...request, params }, options); + ? await asyncSearch(context, request) + : await rollupSearch(context, request); if ( usage && @@ -75,72 +67,75 @@ export const enhancedEsSearchStrategyProvider = ( }); }; - return { search, cancel }; -}; - -async function asyncSearch( - client: ElasticsearchClient, - request: IEnhancedEsSearchRequest, - options?: ISearchOptions -): Promise { - let esResponse; + async function asyncSearch( + context: RequestHandlerContext, + request: IEnhancedEsSearchRequest + ): Promise { + let esResponse; + const esClient = context.core.elasticsearch.client.asCurrentUser; + const uiSettingsClient = await context.core.uiSettings.client; + + const asyncOptions = { + waitForCompletionTimeout: '100ms', // Wait up to 100ms for the response to return + keepAlive: '1m', // Extend the TTL for this search request by one minute + }; + + // If we have an ID, then just poll for that ID, otherwise send the entire request body + if (!request.id) { + const submitOptions = toSnakeCase({ + batchedReduceSize: 64, // Only report partial results every 64 shards; this should be reduced when we actually display partial results + ...(await getDefaultSearchParams(uiSettingsClient)), + ...asyncOptions, + ...request.params, + }); + + esResponse = await esClient.asyncSearch.submit(submitOptions); + } else { + esResponse = await esClient.asyncSearch.get({ + id: request.id, + ...toSnakeCase(asyncOptions), + }); + } - const asyncOptions = { - waitForCompletionTimeout: '100ms', // Wait up to 100ms for the response to return - keepAlive: '1m', // Extend the TTL for this search request by one minute - }; + const { id, response, is_partial: isPartial, is_running: isRunning } = esResponse.body; + return { + id, + isPartial, + isRunning, + rawResponse: shimHitsTotal(response), + ...getTotalLoaded(response._shards), + }; + } - // If we have an ID, then just poll for that ID, otherwise send the entire request body - if (!request.id) { - const submitOptions = toSnakeCase({ - batchedReduceSize: 64, // Only report partial results every 64 shards; this should be reduced when we actually display partial results - trackTotalHits: true, // Get the exact count of hits - ...asyncOptions, - ...request.params, + const rollupSearch = async function ( + context: RequestHandlerContext, + request: IEnhancedEsSearchRequest + ): Promise { + const esClient = context.core.elasticsearch.client.asCurrentUser; + const uiSettingsClient = await context.core.uiSettings.client; + const config = await config$.pipe(first()).toPromise(); + const { body, index, ...params } = request.params!; + const method = 'POST'; + const path = encodeURI(`/${index}/_rollup_search`); + const querystring = toSnakeCase({ + ...getShardTimeout(config), + ...(await getDefaultSearchParams(uiSettingsClient)), + ...params, }); - esResponse = await client.asyncSearch.submit(submitOptions); - } else { - esResponse = await client.asyncSearch.get({ - id: request.id, - ...toSnakeCase(asyncOptions), + const esResponse = await esClient.transport.request({ + method, + path, + body, + querystring, }); - } - - const { id, response, is_partial: isPartial, is_running: isRunning } = esResponse.body; - return { - id, - isPartial, - isRunning, - rawResponse: shimHitsTotal(response), - ...getTotalLoaded(response._shards), - }; -} -async function rollupSearch( - client: ElasticsearchClient, - request: IEnhancedEsSearchRequest, - options?: ISearchOptions -): Promise { - const { body, index, ...params } = request.params!; - const method = 'POST'; - const path = encodeURI(`/${index}/_rollup_search`); - const querystring = toSnakeCase(params); - - const esResponse = await client.transport.request({ - method, - path, - body, - querystring, - }); - - const response = esResponse.body as SearchResponse; - return { - rawResponse: shimHitsTotal(response), - ...getTotalLoaded(response._shards), + const response = esResponse.body as SearchResponse; + return { + rawResponse: response, + ...getTotalLoaded(response._shards), + }; }; -} -function toSnakeCase(obj: Record) { - return mapKeys(obj, (value, key) => snakeCase(key)); -} + return { search, cancel }; +}; diff --git a/x-pack/plugins/data_enhanced/server/search/shim_hits_total.ts b/x-pack/plugins/data_enhanced/server/search/shim_hits_total.ts deleted file mode 100644 index 10d45be01563..000000000000 --- a/x-pack/plugins/data_enhanced/server/search/shim_hits_total.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { SearchResponse } from 'elasticsearch'; - -/** - * Temporary workaround until https://github.com/elastic/kibana/issues/26356 is addressed. - * Since we are setting `track_total_hits` in the request, `hits.total` will be an object - * containing the `value`. - */ -export function shimHitsTotal(response: SearchResponse) { - const total = (response.hits?.total as any)?.value ?? response.hits?.total; - const hits = { ...response.hits, total }; - return { ...response, hits }; -} diff --git a/x-pack/plugins/data_enhanced/server/ui_settings.ts b/x-pack/plugins/data_enhanced/server/ui_settings.ts new file mode 100644 index 000000000000..f2842da8b833 --- /dev/null +++ b/x-pack/plugins/data_enhanced/server/ui_settings.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { schema } from '@kbn/config-schema'; +import { UiSettingsParams } from 'kibana/server'; +import { UI_SETTINGS } from '../../../../src/plugins/data/server'; + +export function getUiSettings(): Record> { + return { + [UI_SETTINGS.SEARCH_TIMEOUT]: { + name: i18n.translate('xpack.data.advancedSettings.searchTimeout', { + defaultMessage: 'Search Timeout', + }), + value: 600000, + description: i18n.translate('xpack.data.advancedSettings.searchTimeoutDesc', { + defaultMessage: + 'Change the maximum timeout for a search session or set to 0 to disable the timeout and allow queries to run to completion.', + }), + type: 'number', + category: ['search'], + schema: schema.number(), + }, + }; +} diff --git a/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts b/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts index 2d31be65dd30..4533383ebd80 100644 --- a/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts +++ b/x-pack/plugins/enterprise_search/common/__mocks__/initial_app_data.ts @@ -7,9 +7,20 @@ export const DEFAULT_INITIAL_APP_DATA = { readOnlyMode: false, ilmEnabled: true, + isFederatedAuth: false, configuredLimits: { - maxDocumentByteSize: 102400, - maxEnginesPerMetaEngine: 15, + appSearch: { + engine: { + maxDocumentByteSize: 102400, + maxEnginesPerMetaEngine: 15, + }, + }, + workplaceSearch: { + customApiSource: { + maxDocumentByteSize: 102400, + totalFields: 64, + }, + }, }, appSearch: { accountId: 'some-id-string', @@ -29,17 +40,16 @@ export const DEFAULT_INITIAL_APP_DATA = { }, }, workplaceSearch: { - canCreateInvitations: true, - isFederatedAuth: false, organization: { name: 'ACME Donuts', defaultOrgName: 'My Organization', }, - fpAccount: { + account: { id: 'some-id-string', groups: ['Default', 'Cats'], isAdmin: true, canCreatePersonalSources: true, + canCreateInvitations: true, isCurated: false, viewedOnboardingPage: true, }, diff --git a/x-pack/plugins/enterprise_search/common/constants.ts b/x-pack/plugins/enterprise_search/common/constants.ts index 05d27d7337a6..c6ca0d532ce0 100644 --- a/x-pack/plugins/enterprise_search/common/constants.ts +++ b/x-pack/plugins/enterprise_search/common/constants.ts @@ -11,7 +11,24 @@ export const ENTERPRISE_SEARCH_PLUGIN = { NAME: i18n.translate('xpack.enterpriseSearch.productName', { defaultMessage: 'Enterprise Search', }), - URL: '/app/enterprise_search', + NAV_TITLE: i18n.translate('xpack.enterpriseSearch.navTitle', { + defaultMessage: 'Overview', + }), + SUBTITLE: i18n.translate('xpack.enterpriseSearch.featureCatalogue.subtitle', { + defaultMessage: 'Search everything', + }), + DESCRIPTIONS: [ + i18n.translate('xpack.enterpriseSearch.featureCatalogueDescription1', { + defaultMessage: 'Build a powerful search experience.', + }), + i18n.translate('xpack.enterpriseSearch.featureCatalogueDescription2', { + defaultMessage: 'Connect your users to relevant data.', + }), + i18n.translate('xpack.enterpriseSearch.featureCatalogueDescription3', { + defaultMessage: 'Unify your team content.', + }), + ], + URL: '/app/enterprise_search/overview', }; export const APP_SEARCH_PLUGIN = { @@ -23,6 +40,10 @@ export const APP_SEARCH_PLUGIN = { defaultMessage: 'Leverage dashboards, analytics, and APIs for advanced application search made simple.', }), + CARD_DESCRIPTION: i18n.translate('xpack.enterpriseSearch.appSearch.productCardDescription', { + defaultMessage: + 'Elastic App Search provides user-friendly tools to design and deploy a powerful search to your websites or web/mobile applications.', + }), URL: '/app/enterprise_search/app_search', SUPPORT_URL: 'https://discuss.elastic.co/c/enterprise-search/app-search/', }; @@ -36,12 +57,22 @@ export const WORKPLACE_SEARCH_PLUGIN = { defaultMessage: 'Search all documents, files, and sources available across your virtual workplace.', }), + CARD_DESCRIPTION: i18n.translate( + 'xpack.enterpriseSearch.workplaceSearch.productCardDescription', + { + defaultMessage: + "Unify all your team's content in one place, with instant connectivity to popular productivity and collaboration tools.", + } + ), URL: '/app/enterprise_search/workplace_search', SUPPORT_URL: 'https://discuss.elastic.co/c/enterprise-search/workplace-search/', }; export const LICENSED_SUPPORT_URL = 'https://support.elastic.co'; -export const JSON_HEADER = { 'Content-Type': 'application/json' }; // This needs specific casing or Chrome throws a 415 error +export const JSON_HEADER = { + 'Content-Type': 'application/json', // This needs specific casing or Chrome throws a 415 error + Accept: 'application/json', // Required for Enterprise Search APIs +}; export const ENGINES_PAGE_SIZE = 10; diff --git a/x-pack/plugins/enterprise_search/common/types/app_search.ts b/x-pack/plugins/enterprise_search/common/types/app_search.ts index 5d6ec079e66e..72259ecd2343 100644 --- a/x-pack/plugins/enterprise_search/common/types/app_search.ts +++ b/x-pack/plugins/enterprise_search/common/types/app_search.ts @@ -23,3 +23,10 @@ export interface IRole { availableRoleTypes: string[]; }; } + +export interface IConfiguredLimits { + engine: { + maxDocumentByteSize: number; + maxEnginesPerMetaEngine: number; + }; +} diff --git a/x-pack/plugins/enterprise_search/common/types/index.ts b/x-pack/plugins/enterprise_search/common/types/index.ts index 008afb234a37..d5774adc0d51 100644 --- a/x-pack/plugins/enterprise_search/common/types/index.ts +++ b/x-pack/plugins/enterprise_search/common/types/index.ts @@ -4,18 +4,29 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IAccount as IAppSearchAccount } from './app_search'; -import { IWorkplaceSearchInitialData } from './workplace_search'; +import { + IAccount as IAppSearchAccount, + IConfiguredLimits as IAppSearchConfiguredLimits, +} from './app_search'; +import { + IWorkplaceSearchInitialData, + IConfiguredLimits as IWorkplaceSearchConfiguredLimits, +} from './workplace_search'; export interface IInitialAppData { readOnlyMode?: boolean; ilmEnabled?: boolean; + isFederatedAuth?: boolean; configuredLimits?: IConfiguredLimits; + access?: { + hasAppSearchAccess: boolean; + hasWorkplaceSearchAccess: boolean; + }; appSearch?: IAppSearchAccount; workplaceSearch?: IWorkplaceSearchInitialData; } export interface IConfiguredLimits { - maxDocumentByteSize: number; - maxEnginesPerMetaEngine: number; + appSearch: IAppSearchConfiguredLimits; + workplaceSearch: IWorkplaceSearchConfiguredLimits; } diff --git a/x-pack/plugins/enterprise_search/common/types/workplace_search.ts b/x-pack/plugins/enterprise_search/common/types/workplace_search.ts index bc4e39b0788d..6c82206706b3 100644 --- a/x-pack/plugins/enterprise_search/common/types/workplace_search.ts +++ b/x-pack/plugins/enterprise_search/common/types/workplace_search.ts @@ -10,6 +10,7 @@ export interface IAccount { isAdmin: boolean; isCurated: boolean; canCreatePersonalSources: boolean; + canCreateInvitations?: boolean; viewedOnboardingPage: boolean; } @@ -19,8 +20,13 @@ export interface IOrganization { } export interface IWorkplaceSearchInitialData { - canCreateInvitations: boolean; - isFederatedAuth: boolean; organization: IOrganization; - fpAccount: IAccount; + account: IAccount; +} + +export interface IConfiguredLimits { + customApiSource: { + maxDocumentByteSize: number; + totalFields: number; + }; } diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/react_router_history.mock.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/react_router_history.mock.ts index 779eb1a043e8..842dcefd3aef 100644 --- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/react_router_history.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/react_router_history.mock.ts @@ -9,7 +9,7 @@ * Jest to accept its use within a jest.mock() */ export const mockHistory = { - createHref: jest.fn(({ pathname }) => `/enterprise_search${pathname}`), + createHref: jest.fn(({ pathname }) => `/app/enterprise_search${pathname}`), push: jest.fn(), location: { pathname: '/current-path', diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/assets/app_search.png b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/assets/app_search.png new file mode 100644 index 000000000000..6cf0639167e2 Binary files /dev/null and b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/assets/app_search.png differ diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/assets/bg_enterprise_search.png b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/assets/bg_enterprise_search.png new file mode 100644 index 000000000000..1b5e1e489fd9 Binary files /dev/null and b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/assets/bg_enterprise_search.png differ diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/assets/workplace_search.png b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/assets/workplace_search.png new file mode 100644 index 000000000000..984662b65cb5 Binary files /dev/null and b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/assets/workplace_search.png differ diff --git a/x-pack/plugins/infra/server/lib/snapshot/constants.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/index.ts similarity index 65% rename from x-pack/plugins/infra/server/lib/snapshot/constants.ts rename to x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/index.ts index 0420878dbcf5..df85a10f7e9d 100644 --- a/x-pack/plugins/infra/server/lib/snapshot/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/index.ts @@ -4,6 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -// TODO: Make SNAPSHOT_COMPOSITE_REQUEST_SIZE configurable from kibana.yml - -export const SNAPSHOT_COMPOSITE_REQUEST_SIZE = 75; +export { ProductCard } from './product_card'; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.scss b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.scss new file mode 100644 index 000000000000..d6b6bd344259 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.scss @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +.productCard { + margin: $euiSizeS; + + &__imageContainer { + max-height: 115px; + overflow: hidden; + background-color: #0076cc; + + @include euiBreakpoint('s', 'm', 'l', 'xl') { + max-height: none; + } + } + + &__image { + width: 100%; + height: auto; + } + + .euiCard__content { + max-width: 350px; + margin-top: $euiSizeL; + + @include euiBreakpoint('s', 'm', 'l', 'xl') { + margin-top: $euiSizeXL; + } + } + + .euiCard__title { + margin-bottom: $euiSizeM; + font-weight: $euiFontWeightBold; + + @include euiBreakpoint('s', 'm', 'l', 'xl') { + margin-bottom: $euiSizeL; + font-size: $euiSizeL; + } + } + + .euiCard__description { + font-weight: $euiFontWeightMedium; + color: $euiColorMediumShade; + margin-bottom: $euiSize; + } + + .euiCard__footer { + margin-bottom: $euiSizeS; + + @include euiBreakpoint('s', 'm', 'l', 'xl') { + margin-bottom: $euiSizeM; + font-size: $euiSizeL; + } + } +} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.test.tsx new file mode 100644 index 000000000000..a76b654ccddd --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.test.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { EuiCard } from '@elastic/eui'; +import { EuiButton } from '../../../shared/react_router_helpers'; +import { APP_SEARCH_PLUGIN, WORKPLACE_SEARCH_PLUGIN } from '../../../../../common/constants'; + +jest.mock('../../../shared/telemetry', () => ({ + sendTelemetry: jest.fn(), +})); +import { sendTelemetry } from '../../../shared/telemetry'; + +import { ProductCard } from './'; + +describe('ProductCard', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders an App Search card', () => { + const wrapper = shallow(); + const card = wrapper.find(EuiCard).dive().shallow(); + + expect(card.find('h2').text()).toEqual('Elastic App Search'); + expect(card.find('.productCard__image').prop('src')).toEqual('as.jpg'); + + const button = card.find(EuiButton); + expect(button.prop('to')).toEqual('/app/enterprise_search/app_search'); + expect(button.prop('data-test-subj')).toEqual('LaunchAppSearchButton'); + + button.simulate('click'); + expect(sendTelemetry).toHaveBeenCalledWith(expect.objectContaining({ metric: 'app_search' })); + }); + + it('renders a Workplace Search card', () => { + const wrapper = shallow(); + const card = wrapper.find(EuiCard).dive().shallow(); + + expect(card.find('h2').text()).toEqual('Elastic Workplace Search'); + expect(card.find('.productCard__image').prop('src')).toEqual('ws.jpg'); + + const button = card.find(EuiButton); + expect(button.prop('to')).toEqual('/app/enterprise_search/workplace_search'); + expect(button.prop('data-test-subj')).toEqual('LaunchWorkplaceSearchButton'); + + button.simulate('click'); + expect(sendTelemetry).toHaveBeenCalledWith( + expect.objectContaining({ metric: 'workplace_search' }) + ); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.tsx new file mode 100644 index 000000000000..334ca126cabb --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_card/product_card.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useContext } from 'react'; +import upperFirst from 'lodash/upperFirst'; +import snakeCase from 'lodash/snakeCase'; +import { i18n } from '@kbn/i18n'; +import { EuiCard, EuiTextColor } from '@elastic/eui'; + +import { EuiButton } from '../../../shared/react_router_helpers'; +import { sendTelemetry } from '../../../shared/telemetry'; +import { KibanaContext, IKibanaContext } from '../../../index'; + +import './product_card.scss'; + +interface IProductCard { + // Expects product plugin constants (@see common/constants.ts) + product: { + ID: string; + NAME: string; + CARD_DESCRIPTION: string; + URL: string; + }; + image: string; +} + +export const ProductCard: React.FC = ({ product, image }) => { + const { http } = useContext(KibanaContext) as IKibanaContext; + + return ( + + + + } + paddingSize="l" + description={{product.CARD_DESCRIPTION}} + footer={ + + sendTelemetry({ + http, + product: 'enterprise_search', + action: 'clicked', + metric: snakeCase(product.ID), + }) + } + data-test-subj={`Launch${upperFirst(product.ID)}Button`} + > + {i18n.translate('xpack.enterpriseSearch.overview.productCard.button', { + defaultMessage: `Launch {productName}`, + values: { productName: product.NAME }, + })} + + } + /> + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.scss b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.scss new file mode 100644 index 000000000000..d93794335231 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.scss @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +.enterpriseSearchOverview { + padding-top: 78px; + background-image: url('./assets/bg_enterprise_search.png'); + background-repeat: no-repeat; + background-size: 670px; + background-position: center -27px; + + @include euiBreakpoint('m', 'l', 'xl') { + padding-top: 158px; + background-size: 1160px; + background-position: center -48px; + } + + &__header { + text-align: center; + margin: auto; + } + + &__heading { + @include euiBreakpoint('xs', 's') { + font-size: $euiFontSizeXL; + line-height: map-get(map-get($euiTitles, 'm'), 'line-height'); + } + } + + &__subheading { + color: $euiColorMediumShade; + font-size: $euiFontSize; + + @include euiBreakpoint('m', 'l', 'xl') { + font-size: $euiFontSizeL; + margin-bottom: $euiSizeL; + } + } + + // EUI override + .euiTitle + .euiTitle { + margin-top: 0; + + @include euiBreakpoint('m', 'l', 'xl') { + margin-top: $euiSizeS; + } + } + + .enterpriseSearchOverview__card { + flex-basis: 50%; + } +} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx new file mode 100644 index 000000000000..cd2a22a45bbb --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.test.tsx @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { EuiPage } from '@elastic/eui'; + +import { EnterpriseSearch } from './'; +import { ProductCard } from './components/product_card'; + +describe('EnterpriseSearch', () => { + it('renders the overview page and product cards', () => { + const wrapper = shallow( + + ); + + expect(wrapper.find(EuiPage).hasClass('enterpriseSearchOverview')).toBe(true); + expect(wrapper.find(ProductCard)).toHaveLength(2); + }); + + describe('access checks', () => { + it('does not render the App Search card if the user does not have access to AS', () => { + const wrapper = shallow( + + ); + + expect(wrapper.find(ProductCard)).toHaveLength(1); + expect(wrapper.find(ProductCard).prop('product').ID).toEqual('workplaceSearch'); + }); + + it('does not render the Workplace Search card if the user does not have access to WS', () => { + const wrapper = shallow( + + ); + + expect(wrapper.find(ProductCard)).toHaveLength(1); + expect(wrapper.find(ProductCard).prop('product').ID).toEqual('appSearch'); + }); + + it('does not render any cards if the user does not have access', () => { + const wrapper = shallow(); + + expect(wrapper.find(ProductCard)).toHaveLength(0); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.tsx new file mode 100644 index 000000000000..373f595a6a9e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.tsx @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { + EuiPage, + EuiPageBody, + EuiPageHeader, + EuiPageHeaderSection, + EuiPageContentBody, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { IInitialAppData } from '../../../common/types'; +import { APP_SEARCH_PLUGIN, WORKPLACE_SEARCH_PLUGIN } from '../../../common/constants'; + +import { SetEnterpriseSearchChrome as SetPageChrome } from '../shared/kibana_chrome'; +import { SendEnterpriseSearchTelemetry as SendTelemetry } from '../shared/telemetry'; + +import { ProductCard } from './components/product_card'; + +import AppSearchImage from './assets/app_search.png'; +import WorkplaceSearchImage from './assets/workplace_search.png'; +import './index.scss'; + +export const EnterpriseSearch: React.FC = ({ access = {} }) => { + const { hasAppSearchAccess, hasWorkplaceSearchAccess } = access; + + return ( + + + + + + + + +

+ {i18n.translate('xpack.enterpriseSearch.overview.heading', { + defaultMessage: 'Welcome to Elastic Enterprise Search', + })} +

+
+ +

+ {i18n.translate('xpack.enterpriseSearch.overview.subheading', { + defaultMessage: 'Select a product to get started', + })} +

+
+
+
+ + + {hasAppSearchAccess && ( + + + + )} + {hasWorkplaceSearchAccess && ( + + + + )} + + + +
+
+ ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.test.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.test.ts index 9e86b239432a..3c8b3a721886 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.test.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.test.ts @@ -37,27 +37,37 @@ describe('useBreadcrumbs', () => { expect(breadcrumb).toEqual([ { text: 'Hello', - href: '/enterprise_search/hello', + href: '/app/enterprise_search/hello', onClick: expect.any(Function), }, { text: 'World', - href: '/enterprise_search/world', + href: '/app/enterprise_search/world', onClick: expect.any(Function), }, ]); }); it('prevents default navigation and uses React Router history on click', () => { - const breadcrumb = useBreadcrumbs([{ text: '', path: '/' }])[0] as any; + const breadcrumb = useBreadcrumbs([{ text: '', path: '/test' }])[0] as any; const event = { preventDefault: jest.fn() }; breadcrumb.onClick(event); - expect(mockKibanaContext.navigateToUrl).toHaveBeenCalled(); + expect(mockKibanaContext.navigateToUrl).toHaveBeenCalledWith('/app/enterprise_search/test'); expect(mockHistory.createHref).toHaveBeenCalled(); expect(event.preventDefault).toHaveBeenCalled(); }); + it('does not call createHref if shouldNotCreateHref is passed', () => { + const breadcrumb = useBreadcrumbs([ + { text: '', path: '/test', shouldNotCreateHref: true }, + ])[0] as any; + breadcrumb.onClick({ preventDefault: () => null }); + + expect(mockKibanaContext.navigateToUrl).toHaveBeenCalledWith('/test'); + expect(mockHistory.createHref).not.toHaveBeenCalled(); + }); + it('does not prevent default browser behavior on new tab/window clicks', () => { const breadcrumb = useBreadcrumbs([{ text: '', path: '/' }])[0] as any; @@ -95,15 +105,17 @@ describe('useEnterpriseSearchBreadcrumbs', () => { expect(useEnterpriseSearchBreadcrumbs(breadcrumbs)).toEqual([ { text: 'Enterprise Search', + href: '/app/enterprise_search/overview', + onClick: expect.any(Function), }, { text: 'Page 1', - href: '/enterprise_search/page1', + href: '/app/enterprise_search/page1', onClick: expect.any(Function), }, { text: 'Page 2', - href: '/enterprise_search/page2', + href: '/app/enterprise_search/page2', onClick: expect.any(Function), }, ]); @@ -113,6 +125,8 @@ describe('useEnterpriseSearchBreadcrumbs', () => { expect(useEnterpriseSearchBreadcrumbs()).toEqual([ { text: 'Enterprise Search', + href: '/app/enterprise_search/overview', + onClick: expect.any(Function), }, ]); }); @@ -122,7 +136,7 @@ describe('useAppSearchBreadcrumbs', () => { beforeEach(() => { jest.clearAllMocks(); mockHistory.createHref.mockImplementation( - ({ pathname }: any) => `/enterprise_search/app_search${pathname}` + ({ pathname }: any) => `/app/enterprise_search/app_search${pathname}` ); }); @@ -141,20 +155,22 @@ describe('useAppSearchBreadcrumbs', () => { expect(useAppSearchBreadcrumbs(breadcrumbs)).toEqual([ { text: 'Enterprise Search', + href: '/app/enterprise_search/overview', + onClick: expect.any(Function), }, { text: 'App Search', - href: '/enterprise_search/app_search/', + href: '/app/enterprise_search/app_search/', onClick: expect.any(Function), }, { text: 'Page 1', - href: '/enterprise_search/app_search/page1', + href: '/app/enterprise_search/app_search/page1', onClick: expect.any(Function), }, { text: 'Page 2', - href: '/enterprise_search/app_search/page2', + href: '/app/enterprise_search/app_search/page2', onClick: expect.any(Function), }, ]); @@ -164,10 +180,12 @@ describe('useAppSearchBreadcrumbs', () => { expect(useAppSearchBreadcrumbs()).toEqual([ { text: 'Enterprise Search', + href: '/app/enterprise_search/overview', + onClick: expect.any(Function), }, { text: 'App Search', - href: '/enterprise_search/app_search/', + href: '/app/enterprise_search/app_search/', onClick: expect.any(Function), }, ]); @@ -178,7 +196,7 @@ describe('useWorkplaceSearchBreadcrumbs', () => { beforeEach(() => { jest.clearAllMocks(); mockHistory.createHref.mockImplementation( - ({ pathname }: any) => `/enterprise_search/workplace_search${pathname}` + ({ pathname }: any) => `/app/enterprise_search/workplace_search${pathname}` ); }); @@ -197,20 +215,22 @@ describe('useWorkplaceSearchBreadcrumbs', () => { expect(useWorkplaceSearchBreadcrumbs(breadcrumbs)).toEqual([ { text: 'Enterprise Search', + href: '/app/enterprise_search/overview', + onClick: expect.any(Function), }, { text: 'Workplace Search', - href: '/enterprise_search/workplace_search/', + href: '/app/enterprise_search/workplace_search/', onClick: expect.any(Function), }, { text: 'Page 1', - href: '/enterprise_search/workplace_search/page1', + href: '/app/enterprise_search/workplace_search/page1', onClick: expect.any(Function), }, { text: 'Page 2', - href: '/enterprise_search/workplace_search/page2', + href: '/app/enterprise_search/workplace_search/page2', onClick: expect.any(Function), }, ]); @@ -220,10 +240,12 @@ describe('useWorkplaceSearchBreadcrumbs', () => { expect(useWorkplaceSearchBreadcrumbs()).toEqual([ { text: 'Enterprise Search', + href: '/app/enterprise_search/overview', + onClick: expect.any(Function), }, { text: 'Workplace Search', - href: '/enterprise_search/workplace_search/', + href: '/app/enterprise_search/workplace_search/', onClick: expect.any(Function), }, ]); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts index 6eab936719d0..19714608e73e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_breadcrumbs.ts @@ -26,6 +26,9 @@ import { letBrowserHandleEvent } from '../react_router_helpers'; interface IBreadcrumb { text: string; path?: string; + // Used to navigate outside of the React Router basename, + // i.e. if we need to go from App Search to Enterprise Search + shouldNotCreateHref?: boolean; } export type TBreadcrumbs = IBreadcrumb[]; @@ -33,11 +36,11 @@ export const useBreadcrumbs = (breadcrumbs: TBreadcrumbs) => { const history = useHistory(); const { navigateToUrl } = useContext(KibanaContext) as IKibanaContext; - return breadcrumbs.map(({ text, path }) => { + return breadcrumbs.map(({ text, path, shouldNotCreateHref }) => { const breadcrumb = { text } as EuiBreadcrumb; if (path) { - const href = history.createHref({ pathname: path }) as string; + const href = shouldNotCreateHref ? path : (history.createHref({ pathname: path }) as string); breadcrumb.href = href; breadcrumb.onClick = (event) => { @@ -56,7 +59,14 @@ export const useBreadcrumbs = (breadcrumbs: TBreadcrumbs) => { */ export const useEnterpriseSearchBreadcrumbs = (breadcrumbs: TBreadcrumbs = []) => - useBreadcrumbs([{ text: ENTERPRISE_SEARCH_PLUGIN.NAME }, ...breadcrumbs]); + useBreadcrumbs([ + { + text: ENTERPRISE_SEARCH_PLUGIN.NAME, + path: ENTERPRISE_SEARCH_PLUGIN.URL, + shouldNotCreateHref: true, + }, + ...breadcrumbs, + ]); export const useAppSearchBreadcrumbs = (breadcrumbs: TBreadcrumbs = []) => useEnterpriseSearchBreadcrumbs([{ text: APP_SEARCH_PLUGIN.NAME, path: '/' }, ...breadcrumbs]); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_title.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_title.ts index 706baefc00cc..de5f72de7919 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_title.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/generate_title.ts @@ -20,7 +20,7 @@ export type TTitle = string[]; /** * Given an array of page titles, return a final formatted document title * @param pages - e.g., ['Curations', 'some Engine', 'App Search'] - * @returns - e.g., 'Curations | some Engine | App Search' + * @returns - e.g., 'Curations - some Engine - App Search' */ export const generateTitle = (pages: TTitle) => pages.join(' - '); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/index.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/index.ts index 4468d11ba94c..02013a03c339 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/index.ts @@ -4,4 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -export { SetAppSearchChrome, SetWorkplaceSearchChrome } from './set_chrome'; +export { + SetEnterpriseSearchChrome, + SetAppSearchChrome, + SetWorkplaceSearchChrome, +} from './set_chrome'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.test.tsx index bda816c9a555..61a066bb9221 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.test.tsx @@ -12,18 +12,24 @@ import React from 'react'; import { mockKibanaContext, mountWithKibanaContext } from '../../__mocks__'; jest.mock('./generate_breadcrumbs', () => ({ + useEnterpriseSearchBreadcrumbs: jest.fn(() => (crumbs: any) => crumbs), useAppSearchBreadcrumbs: jest.fn(() => (crumbs: any) => crumbs), useWorkplaceSearchBreadcrumbs: jest.fn(() => (crumbs: any) => crumbs), })); -import { useAppSearchBreadcrumbs, useWorkplaceSearchBreadcrumbs } from './generate_breadcrumbs'; +import { + useEnterpriseSearchBreadcrumbs, + useAppSearchBreadcrumbs, + useWorkplaceSearchBreadcrumbs, +} from './generate_breadcrumbs'; jest.mock('./generate_title', () => ({ + enterpriseSearchTitle: jest.fn((title: any) => title), appSearchTitle: jest.fn((title: any) => title), workplaceSearchTitle: jest.fn((title: any) => title), })); -import { appSearchTitle, workplaceSearchTitle } from './generate_title'; +import { enterpriseSearchTitle, appSearchTitle, workplaceSearchTitle } from './generate_title'; -import { SetAppSearchChrome, SetWorkplaceSearchChrome } from './'; +import { SetEnterpriseSearchChrome, SetAppSearchChrome, SetWorkplaceSearchChrome } from './'; describe('Set Kibana Chrome helpers', () => { beforeEach(() => { @@ -35,6 +41,27 @@ describe('Set Kibana Chrome helpers', () => { expect(mockKibanaContext.setDocTitle).toHaveBeenCalled(); }); + describe('SetEnterpriseSearchChrome', () => { + it('sets breadcrumbs and document title', () => { + mountWithKibanaContext(); + + expect(enterpriseSearchTitle).toHaveBeenCalledWith(['Hello World']); + expect(useEnterpriseSearchBreadcrumbs).toHaveBeenCalledWith([ + { + text: 'Hello World', + path: '/current-path', + }, + ]); + }); + + it('sets empty breadcrumbs and document title when isRoot is true', () => { + mountWithKibanaContext(); + + expect(enterpriseSearchTitle).toHaveBeenCalledWith([]); + expect(useEnterpriseSearchBreadcrumbs).toHaveBeenCalledWith([]); + }); + }); + describe('SetAppSearchChrome', () => { it('sets breadcrumbs and document title', () => { mountWithKibanaContext(); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.tsx index 43db93c1583d..5e8d972e1a13 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana_chrome/set_chrome.tsx @@ -10,11 +10,17 @@ import { EuiBreadcrumb } from '@elastic/eui'; import { KibanaContext, IKibanaContext } from '../../index'; import { + useEnterpriseSearchBreadcrumbs, useAppSearchBreadcrumbs, useWorkplaceSearchBreadcrumbs, TBreadcrumbs, } from './generate_breadcrumbs'; -import { appSearchTitle, workplaceSearchTitle, TTitle } from './generate_title'; +import { + enterpriseSearchTitle, + appSearchTitle, + workplaceSearchTitle, + TTitle, +} from './generate_title'; /** * Helpers for setting Kibana chrome (breadcrumbs, doc titles) on React view mount @@ -33,6 +39,24 @@ interface IRootBreadcrumbsProps { } type TBreadcrumbsProps = IBreadcrumbsProps | IRootBreadcrumbsProps; +export const SetEnterpriseSearchChrome: React.FC = ({ text, isRoot }) => { + const history = useHistory(); + const { setBreadcrumbs, setDocTitle } = useContext(KibanaContext) as IKibanaContext; + + const title = isRoot ? [] : [text]; + const docTitle = enterpriseSearchTitle(title as TTitle | []); + + const crumb = isRoot ? [] : [{ text, path: history.location.pathname }]; + const breadcrumbs = useEnterpriseSearchBreadcrumbs(crumb as TBreadcrumbs | []); + + useEffect(() => { + setBreadcrumbs(breadcrumbs); + setDocTitle(docTitle); + }, []); + + return null; +}; + export const SetAppSearchChrome: React.FC = ({ text, isRoot }) => { const history = useHistory(); const { setBreadcrumbs, setDocTitle } = useContext(KibanaContext) as IKibanaContext; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_link.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_link.test.tsx index 063118f94cd1..0c7bac99085d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_link.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_link.test.tsx @@ -45,10 +45,18 @@ describe('EUI & React Router Component Helpers', () => { const link = wrapper.find(EuiLink); expect(link.prop('onClick')).toBeInstanceOf(Function); - expect(link.prop('href')).toEqual('/enterprise_search/foo/bar'); + expect(link.prop('href')).toEqual('/app/enterprise_search/foo/bar'); expect(mockHistory.createHref).toHaveBeenCalled(); }); + it('renders with the correct non-basenamed href when shouldNotCreateHref is passed', () => { + const wrapper = mount(); + const link = wrapper.find(EuiLink); + + expect(link.prop('href')).toEqual('/foo/bar'); + expect(mockHistory.createHref).not.toHaveBeenCalled(); + }); + describe('onClick', () => { it('prevents default navigation and uses React Router history', () => { const wrapper = mount(); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_link.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_link.tsx index 7221a61d0997..e3b46632ddf9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_link.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/react_router_helpers/eui_link.tsx @@ -21,14 +21,22 @@ import { letBrowserHandleEvent } from './link_events'; interface IEuiReactRouterProps { to: string; onClick?(): void; + // Used to navigate outside of the React Router plugin basename but still within Kibana, + // e.g. if we need to go from Enterprise Search to App Search + shouldNotCreateHref?: boolean; } -export const EuiReactRouterHelper: React.FC = ({ to, onClick, children }) => { +export const EuiReactRouterHelper: React.FC = ({ + to, + onClick, + shouldNotCreateHref, + children, +}) => { const history = useHistory(); const { navigateToUrl } = useContext(KibanaContext) as IKibanaContext; // Generate the correct link href (with basename etc. accounted for) - const href = history.createHref({ pathname: to }); + const href = shouldNotCreateHref ? to : history.createHref({ pathname: to }); const reactRouterLinkClick = (event: React.MouseEvent) => { if (onClick) onClick(); // Run any passed click events (e.g. telemetry) @@ -51,9 +59,10 @@ type TEuiReactRouterButtonProps = EuiButtonProps & IEuiReactRouterProps; export const EuiReactRouterLink: React.FC = ({ to, onClick, + shouldNotCreateHref, ...rest }) => ( - + ); @@ -61,9 +70,10 @@ export const EuiReactRouterLink: React.FC = ({ export const EuiReactRouterButton: React.FC = ({ to, onClick, + shouldNotCreateHref, ...rest }) => ( - + ); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/index.ts b/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/index.ts index eadf7fa80559..a8b9636c3ff3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/index.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/index.ts @@ -5,5 +5,8 @@ */ export { sendTelemetry } from './send_telemetry'; -export { SendAppSearchTelemetry } from './send_telemetry'; -export { SendWorkplaceSearchTelemetry } from './send_telemetry'; +export { + SendEnterpriseSearchTelemetry, + SendAppSearchTelemetry, + SendWorkplaceSearchTelemetry, +} from './send_telemetry'; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.test.tsx index 3c873dbc25e3..8f7cf090e2d5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.test.tsx @@ -10,7 +10,12 @@ import { httpServiceMock } from 'src/core/public/mocks'; import { JSON_HEADER as headers } from '../../../../common/constants'; import { mountWithKibanaContext } from '../../__mocks__'; -import { sendTelemetry, SendAppSearchTelemetry, SendWorkplaceSearchTelemetry } from './'; +import { + sendTelemetry, + SendEnterpriseSearchTelemetry, + SendAppSearchTelemetry, + SendWorkplaceSearchTelemetry, +} from './'; describe('Shared Telemetry Helpers', () => { const httpMock = httpServiceMock.createSetupContract(); @@ -44,6 +49,17 @@ describe('Shared Telemetry Helpers', () => { }); describe('React component helpers', () => { + it('SendEnterpriseSearchTelemetry component', () => { + mountWithKibanaContext(, { + http: httpMock, + }); + + expect(httpMock.put).toHaveBeenCalledWith('/api/enterprise_search/telemetry', { + headers, + body: '{"product":"enterprise_search","action":"viewed","metric":"page"}', + }); + }); + it('SendAppSearchTelemetry component', () => { mountWithKibanaContext(, { http: httpMock, @@ -56,13 +72,13 @@ describe('Shared Telemetry Helpers', () => { }); it('SendWorkplaceSearchTelemetry component', () => { - mountWithKibanaContext(, { + mountWithKibanaContext(, { http: httpMock, }); expect(httpMock.put).toHaveBeenCalledWith('/api/enterprise_search/telemetry', { headers, - body: '{"product":"workplace_search","action":"viewed","metric":"page"}', + body: '{"product":"workplace_search","action":"error","metric":"not_found"}', }); }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.tsx index 715d61b31512..4df1428221de 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/telemetry/send_telemetry.tsx @@ -35,9 +35,21 @@ export const sendTelemetry = async ({ http, product, action, metric }: ISendTele /** * React component helpers - useful for on-page-load/views - * TODO: SendEnterpriseSearchTelemetry */ +export const SendEnterpriseSearchTelemetry: React.FC = ({ + action, + metric, +}) => { + const { http } = useContext(KibanaContext) as IKibanaContext; + + useEffect(() => { + sendTelemetry({ http, action, metric, product: 'enterprise_search' }); + }, [action, metric, http]); + + return null; +}; + export const SendAppSearchTelemetry: React.FC = ({ action, metric }) => { const { http } = useContext(KibanaContext) as IKibanaContext; diff --git a/x-pack/plugins/enterprise_search/public/plugin.ts b/x-pack/plugins/enterprise_search/public/plugin.ts index 83598a0dc971..b735db7c4952 100644 --- a/x-pack/plugins/enterprise_search/public/plugin.ts +++ b/x-pack/plugins/enterprise_search/public/plugin.ts @@ -12,7 +12,6 @@ import { AppMountParameters, HttpSetup, } from 'src/core/public'; -import { i18n } from '@kbn/i18n'; import { FeatureCatalogueCategory, HomePublicPluginSetup, @@ -52,6 +51,25 @@ export class EnterpriseSearchPlugin implements Plugin { } public setup(core: CoreSetup, plugins: PluginsSetup) { + core.application.register({ + id: ENTERPRISE_SEARCH_PLUGIN.ID, + title: ENTERPRISE_SEARCH_PLUGIN.NAV_TITLE, + appRoute: ENTERPRISE_SEARCH_PLUGIN.URL, + category: DEFAULT_APP_CATEGORIES.enterpriseSearch, + mount: async (params: AppMountParameters) => { + const [coreStart] = await core.getStartServices(); + const { chrome } = coreStart; + chrome.docTitle.change(ENTERPRISE_SEARCH_PLUGIN.NAME); + + await this.getInitialData(coreStart.http); + + const { renderApp } = await import('./applications'); + const { EnterpriseSearch } = await import('./applications/enterprise_search'); + + return renderApp(EnterpriseSearch, params, coreStart, plugins, this.config, this.data); + }, + }); + core.application.register({ id: APP_SEARCH_PLUGIN.ID, title: APP_SEARCH_PLUGIN.NAME, @@ -94,22 +112,10 @@ export class EnterpriseSearchPlugin implements Plugin { plugins.home.featureCatalogue.registerSolution({ id: ENTERPRISE_SEARCH_PLUGIN.ID, title: ENTERPRISE_SEARCH_PLUGIN.NAME, - subtitle: i18n.translate('xpack.enterpriseSearch.featureCatalogue.subtitle', { - defaultMessage: 'Search everything', - }), + subtitle: ENTERPRISE_SEARCH_PLUGIN.SUBTITLE, icon: 'logoEnterpriseSearch', - descriptions: [ - i18n.translate('xpack.enterpriseSearch.featureCatalogueDescription1', { - defaultMessage: 'Build a powerful search experience.', - }), - i18n.translate('xpack.enterpriseSearch.featureCatalogueDescription2', { - defaultMessage: 'Connect your users to relevant data.', - }), - i18n.translate('xpack.enterpriseSearch.featureCatalogueDescription3', { - defaultMessage: 'Unify your team content.', - }), - ], - path: APP_SEARCH_PLUGIN.URL, // TODO: Change this to enterprise search overview page once available + descriptions: ENTERPRISE_SEARCH_PLUGIN.DESCRIPTIONS, + path: ENTERPRISE_SEARCH_PLUGIN.URL, }); plugins.home.featureCatalogue.register({ diff --git a/x-pack/plugins/enterprise_search/server/collectors/enterprise_search/telemetry.test.ts b/x-pack/plugins/enterprise_search/server/collectors/enterprise_search/telemetry.test.ts new file mode 100644 index 000000000000..c3e2aff6551c --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/collectors/enterprise_search/telemetry.test.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { mockLogger } from '../../__mocks__'; + +import { registerTelemetryUsageCollector } from './telemetry'; + +describe('Enterprise Search Telemetry Usage Collector', () => { + const makeUsageCollectorStub = jest.fn(); + const registerStub = jest.fn(); + const usageCollectionMock = { + makeUsageCollector: makeUsageCollectorStub, + registerCollector: registerStub, + } as any; + + const savedObjectsRepoStub = { + get: () => ({ + attributes: { + 'ui_viewed.overview': 10, + 'ui_clicked.app_search': 2, + 'ui_clicked.workplace_search': 3, + }, + }), + incrementCounter: jest.fn(), + }; + const savedObjectsMock = { + createInternalRepository: jest.fn(() => savedObjectsRepoStub), + } as any; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('registerTelemetryUsageCollector', () => { + it('should make and register the usage collector', () => { + registerTelemetryUsageCollector(usageCollectionMock, savedObjectsMock, mockLogger); + + expect(registerStub).toHaveBeenCalledTimes(1); + expect(makeUsageCollectorStub).toHaveBeenCalledTimes(1); + expect(makeUsageCollectorStub.mock.calls[0][0].type).toBe('enterprise_search'); + expect(makeUsageCollectorStub.mock.calls[0][0].isReady()).toBe(true); + }); + }); + + describe('fetchTelemetryMetrics', () => { + it('should return existing saved objects data', async () => { + registerTelemetryUsageCollector(usageCollectionMock, savedObjectsMock, mockLogger); + const savedObjectsCounts = await makeUsageCollectorStub.mock.calls[0][0].fetch(); + + expect(savedObjectsCounts).toEqual({ + ui_viewed: { + overview: 10, + }, + ui_clicked: { + app_search: 2, + workplace_search: 3, + }, + }); + }); + + it('should return a default telemetry object if no saved data exists', async () => { + const emptySavedObjectsMock = { + createInternalRepository: () => ({ + get: () => ({ attributes: null }), + }), + } as any; + + registerTelemetryUsageCollector(usageCollectionMock, emptySavedObjectsMock, mockLogger); + const savedObjectsCounts = await makeUsageCollectorStub.mock.calls[0][0].fetch(); + + expect(savedObjectsCounts).toEqual({ + ui_viewed: { + overview: 0, + }, + ui_clicked: { + app_search: 0, + workplace_search: 0, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/enterprise_search/server/collectors/enterprise_search/telemetry.ts b/x-pack/plugins/enterprise_search/server/collectors/enterprise_search/telemetry.ts new file mode 100644 index 000000000000..a124a185b9a3 --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/collectors/enterprise_search/telemetry.ts @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { get } from 'lodash'; +import { SavedObjectsServiceStart, Logger } from 'src/core/server'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; + +import { getSavedObjectAttributesFromRepo } from '../lib/telemetry'; + +interface ITelemetry { + ui_viewed: { + overview: number; + }; + ui_clicked: { + app_search: number; + workplace_search: number; + }; +} + +export const ES_TELEMETRY_NAME = 'enterprise_search_telemetry'; + +/** + * Register the telemetry collector + */ + +export const registerTelemetryUsageCollector = ( + usageCollection: UsageCollectionSetup, + savedObjects: SavedObjectsServiceStart, + log: Logger +) => { + const telemetryUsageCollector = usageCollection.makeUsageCollector({ + type: 'enterprise_search', + fetch: async () => fetchTelemetryMetrics(savedObjects, log), + isReady: () => true, + schema: { + ui_viewed: { + overview: { type: 'long' }, + }, + ui_clicked: { + app_search: { type: 'long' }, + workplace_search: { type: 'long' }, + }, + }, + }); + usageCollection.registerCollector(telemetryUsageCollector); +}; + +/** + * Fetch the aggregated telemetry metrics from our saved objects + */ + +const fetchTelemetryMetrics = async (savedObjects: SavedObjectsServiceStart, log: Logger) => { + const savedObjectsRepository = savedObjects.createInternalRepository(); + const savedObjectAttributes = await getSavedObjectAttributesFromRepo( + ES_TELEMETRY_NAME, + savedObjectsRepository, + log + ); + + const defaultTelemetrySavedObject: ITelemetry = { + ui_viewed: { + overview: 0, + }, + ui_clicked: { + app_search: 0, + workplace_search: 0, + }, + }; + + // If we don't have an existing/saved telemetry object, return the default + if (!savedObjectAttributes) { + return defaultTelemetrySavedObject; + } + + return { + ui_viewed: { + overview: get(savedObjectAttributes, 'ui_viewed.overview', 0), + }, + ui_clicked: { + app_search: get(savedObjectAttributes, 'ui_clicked.app_search', 0), + workplace_search: get(savedObjectAttributes, 'ui_clicked.workplace_search', 0), + }, + } as ITelemetry; +}; diff --git a/x-pack/plugins/enterprise_search/server/collectors/lib/telemetry.test.ts b/x-pack/plugins/enterprise_search/server/collectors/lib/telemetry.test.ts index aae162c23ccb..6cf0be9fd1f3 100644 --- a/x-pack/plugins/enterprise_search/server/collectors/lib/telemetry.test.ts +++ b/x-pack/plugins/enterprise_search/server/collectors/lib/telemetry.test.ts @@ -15,7 +15,7 @@ import { SavedObjectsErrorHelpers } from '../../../../../../src/core/server'; import { getSavedObjectAttributesFromRepo, incrementUICounter } from './telemetry'; -describe('App Search Telemetry Usage Collector', () => { +describe('Telemetry helpers', () => { beforeEach(() => { jest.clearAllMocks(); }); diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts index 323f79e63bc6..8e3ae2cfbeb8 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts @@ -38,51 +38,63 @@ describe('callEnterpriseSearchConfigAPI', () => { external_url: 'http://some.vanity.url/', read_only_mode: false, ilm_enabled: true, + is_federated_auth: false, configured_limits: { - max_document_byte_size: 102400, - max_engines_per_meta_engine: 15, + app_search: { + engine: { + document_size_in_bytes: 102400, + source_engines_per_meta_engine: 15, + }, + }, + workplace_search: { + custom_api_source: { + document_size_in_bytes: 102400, + total_fields: 64, + }, + }, + }, + }, + current_user: { + name: 'someuser', + access: { + app_search: true, + workplace_search: false, }, app_search: { - account_id: 'some-id-string', - onboarding_complete: true, + account: { + id: 'some-id-string', + onboarding_complete: true, + }, + role: { + id: 'account_id:somestring|user_oid:somestring', + role_type: 'owner', + ability: { + access_all_engines: true, + destroy: ['session'], + manage: ['account_credentials', 'account_engines'], // etc + edit: ['LocoMoco::Account'], // etc + view: ['Engine'], // etc + credential_types: ['admin', 'private', 'search'], + available_role_types: ['owner', 'admin'], + }, + }, }, workplace_search: { - can_create_invitations: true, - is_federated_auth: false, organization: { name: 'ACME Donuts', default_org_name: 'My Organization', }, - fp_account: { + account: { id: 'some-id-string', groups: ['Default', 'Cats'], is_admin: true, can_create_personal_sources: true, + can_create_invitations: true, is_curated: false, viewed_onboarding_page: true, }, }, }, - current_user: { - name: 'someuser', - access: { - app_search: true, - workplace_search: false, - }, - app_search_role: { - id: 'account_id:somestring|user_oid:somestring', - role_type: 'owner', - ability: { - access_all_engines: true, - destroy: ['session'], - manage: ['account_credentials', 'account_engines'], // etc - edit: ['LocoMoco::Account'], // etc - view: ['Engine'], // etc - credential_types: ['admin', 'private', 'search'], - available_role_types: ['owner', 'admin'], - }, - }, - }, }; beforeEach(() => { @@ -91,7 +103,7 @@ describe('callEnterpriseSearchConfigAPI', () => { it('calls the config API endpoint', async () => { fetchMock.mockImplementationOnce((url: string) => { - expect(url).toEqual('http://localhost:3002/api/ent/v1/internal/client_config'); + expect(url).toEqual('http://localhost:3002/api/ent/v2/internal/client_config'); return Promise.resolve(new Response(JSON.stringify(mockResponse))); }); @@ -116,9 +128,20 @@ describe('callEnterpriseSearchConfigAPI', () => { publicUrl: undefined, readOnlyMode: false, ilmEnabled: false, + isFederatedAuth: false, configuredLimits: { - maxDocumentByteSize: undefined, - maxEnginesPerMetaEngine: undefined, + appSearch: { + engine: { + maxDocumentByteSize: undefined, + maxEnginesPerMetaEngine: undefined, + }, + }, + workplaceSearch: { + customApiSource: { + maxDocumentByteSize: undefined, + totalFields: undefined, + }, + }, }, appSearch: { accountId: undefined, @@ -138,17 +161,16 @@ describe('callEnterpriseSearchConfigAPI', () => { }, }, workplaceSearch: { - canCreateInvitations: false, - isFederatedAuth: false, organization: { name: undefined, defaultOrgName: undefined, }, - fpAccount: { + account: { id: undefined, groups: [], isAdmin: false, canCreatePersonalSources: false, + canCreateInvitations: false, isCurated: false, viewedOnboardingPage: false, }, diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts index c9cbec15169d..10a75e59cb24 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.ts @@ -29,7 +29,7 @@ interface IReturn extends IInitialAppData { * useful various settings (e.g. product access, external URL) * needed by the Kibana plugin at the setup stage */ -const ENDPOINT = '/api/ent/v1/internal/client_config'; +const ENDPOINT = '/api/ent/v2/internal/client_config'; export const callEnterpriseSearchConfigAPI = async ({ config, @@ -67,44 +67,60 @@ export const callEnterpriseSearchConfigAPI = async ({ publicUrl: stripTrailingSlash(data?.settings?.external_url), readOnlyMode: !!data?.settings?.read_only_mode, ilmEnabled: !!data?.settings?.ilm_enabled, + isFederatedAuth: !!data?.settings?.is_federated_auth, // i.e., not standard auth configuredLimits: { - maxDocumentByteSize: data?.settings?.configured_limits?.max_document_byte_size, - maxEnginesPerMetaEngine: data?.settings?.configured_limits?.max_engines_per_meta_engine, + appSearch: { + engine: { + maxDocumentByteSize: + data?.settings?.configured_limits?.app_search?.engine?.document_size_in_bytes, + maxEnginesPerMetaEngine: + data?.settings?.configured_limits?.app_search?.engine?.source_engines_per_meta_engine, + }, + }, + workplaceSearch: { + customApiSource: { + maxDocumentByteSize: + data?.settings?.configured_limits?.workplace_search?.custom_api_source + ?.document_size_in_bytes, + totalFields: + data?.settings?.configured_limits?.workplace_search?.custom_api_source?.total_fields, + }, + }, }, appSearch: { - accountId: data?.settings?.app_search?.account_id, - onBoardingComplete: !!data?.settings?.app_search?.onboarding_complete, + accountId: data?.current_user?.app_search?.account?.id, + onBoardingComplete: !!data?.current_user?.app_search?.account?.onboarding_complete, role: { - id: data?.current_user?.app_search_role?.id, - roleType: data?.current_user?.app_search_role?.role_type, + id: data?.current_user?.app_search?.role?.id, + roleType: data?.current_user?.app_search?.role?.role_type, ability: { - accessAllEngines: !!data?.current_user?.app_search_role?.ability?.access_all_engines, - destroy: data?.current_user?.app_search_role?.ability?.destroy || [], - manage: data?.current_user?.app_search_role?.ability?.manage || [], - edit: data?.current_user?.app_search_role?.ability?.edit || [], - view: data?.current_user?.app_search_role?.ability?.view || [], - credentialTypes: data?.current_user?.app_search_role?.ability?.credential_types || [], + accessAllEngines: !!data?.current_user?.app_search?.role?.ability?.access_all_engines, + destroy: data?.current_user?.app_search?.role?.ability?.destroy || [], + manage: data?.current_user?.app_search?.role?.ability?.manage || [], + edit: data?.current_user?.app_search?.role?.ability?.edit || [], + view: data?.current_user?.app_search?.role?.ability?.view || [], + credentialTypes: data?.current_user?.app_search?.role?.ability?.credential_types || [], availableRoleTypes: - data?.current_user?.app_search_role?.ability?.available_role_types || [], + data?.current_user?.app_search?.role?.ability?.available_role_types || [], }, }, }, workplaceSearch: { - canCreateInvitations: !!data?.settings?.workplace_search?.can_create_invitations, - isFederatedAuth: !!data?.settings?.workplace_search?.is_federated_auth, organization: { - name: data?.settings?.workplace_search?.organization?.name, - defaultOrgName: data?.settings?.workplace_search?.organization?.default_org_name, + name: data?.current_user?.workplace_search?.organization?.name, + defaultOrgName: data?.current_user?.workplace_search?.organization?.default_org_name, }, - fpAccount: { - id: data?.settings?.workplace_search?.fp_account.id, - groups: data?.settings?.workplace_search?.fp_account.groups || [], - isAdmin: !!data?.settings?.workplace_search?.fp_account?.is_admin, - canCreatePersonalSources: !!data?.settings?.workplace_search?.fp_account + account: { + id: data?.current_user?.workplace_search?.account?.id, + groups: data?.current_user?.workplace_search?.account?.groups || [], + isAdmin: !!data?.current_user?.workplace_search?.account?.is_admin, + canCreatePersonalSources: !!data?.current_user?.workplace_search?.account ?.can_create_personal_sources, - isCurated: !!data?.settings?.workplace_search?.fp_account.is_curated, - viewedOnboardingPage: !!data?.settings?.workplace_search?.fp_account - .viewed_onboarding_page, + canCreateInvitations: !!data?.current_user?.workplace_search?.account + ?.can_create_invitations, + isCurated: !!data?.current_user?.workplace_search?.account?.is_curated, + viewedOnboardingPage: !!data?.current_user?.workplace_search?.account + ?.viewed_onboarding_page, }, }, }; diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts index 3f3f18243314..34f83ef3a3fd 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts @@ -5,6 +5,7 @@ */ import { mockConfig, mockLogger } from '../__mocks__'; +import { JSON_HEADER } from '../../common/constants'; import { EnterpriseSearchRequestHandler } from './enterprise_search_request_handler'; @@ -150,18 +151,26 @@ describe('EnterpriseSearchRequestHandler', () => { ); }); - it('returns an error when user authentication to Enterprise Search fails', async () => { - EnterpriseSearchAPI.mockReturn({}, { url: 'http://localhost:3002/login' }); - const requestHandler = enterpriseSearchRequestHandler.createRequest({ - path: '/api/unauthenticated', + describe('user authentication errors', () => { + afterEach(async () => { + const requestHandler = enterpriseSearchRequestHandler.createRequest({ + path: '/api/unauthenticated', + }); + await makeAPICall(requestHandler); + + EnterpriseSearchAPI.shouldHaveBeenCalledWith('http://localhost:3002/api/unauthenticated'); + expect(responseMock.customError).toHaveBeenCalledWith({ + body: 'Error connecting to Enterprise Search: Cannot authenticate Enterprise Search user', + statusCode: 502, + }); }); - await makeAPICall(requestHandler); - EnterpriseSearchAPI.shouldHaveBeenCalledWith('http://localhost:3002/api/unauthenticated'); + it('errors when redirected to /login', async () => { + EnterpriseSearchAPI.mockReturn({}, { url: 'http://localhost:3002/login' }); + }); - expect(responseMock.customError).toHaveBeenCalledWith({ - body: 'Error connecting to Enterprise Search: Cannot authenticate Enterprise Search user', - statusCode: 502, + it('errors when redirected to /ent/select', async () => { + EnterpriseSearchAPI.mockReturn({}, { url: 'http://localhost:3002/ent/select' }); }); }); }); @@ -185,7 +194,7 @@ const makeAPICall = (handler: Function, params = {}) => { const EnterpriseSearchAPI = { shouldHaveBeenCalledWith(expectedUrl: string, expectedParams = {}) { expect(fetchMock).toHaveBeenCalledWith(expectedUrl, { - headers: { Authorization: 'Basic 123' }, + headers: { Authorization: 'Basic 123', ...JSON_HEADER }, method: 'GET', body: undefined, ...expectedParams, diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts index 8f31bd9063d4..18f10c590847 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts @@ -14,6 +14,7 @@ import { Logger, } from 'src/core/server'; import { ConfigType } from '../index'; +import { JSON_HEADER } from '../../common/constants'; interface IConstructorDependencies { config: ConfigType; @@ -25,7 +26,7 @@ interface IRequestParams { hasValidData?: (body?: ResponseBody) => boolean; } export interface IEnterpriseSearchRequestHandler { - createRequest(requestParams?: object): RequestHandler, unknown>; + createRequest(requestParams?: object): RequestHandler; } /** @@ -52,12 +53,12 @@ export class EnterpriseSearchRequestHandler { }: IRequestParams) { return async ( _context: RequestHandlerContext, - request: KibanaRequest, unknown>, + request: KibanaRequest, response: KibanaResponseFactory ) => { try { // Set up API URL - const queryParams = { ...request.query, ...params }; + const queryParams = { ...(request.query as object), ...params }; const queryString = !this.isEmptyObj(queryParams) ? `?${querystring.stringify(queryParams)}` : ''; @@ -65,7 +66,7 @@ export class EnterpriseSearchRequestHandler { // Set up API options const { method } = request.route; - const headers = { Authorization: request.headers.authorization as string }; + const headers = { Authorization: request.headers.authorization as string, ...JSON_HEADER }; const body = !this.isEmptyObj(request.body as object) ? JSON.stringify(request.body) : undefined; @@ -73,7 +74,7 @@ export class EnterpriseSearchRequestHandler { // Call the Enterprise Search API and pass back response to the front-end const apiResponse = await fetch(url, { method, headers, body }); - if (apiResponse.url.endsWith('/login')) { + if (apiResponse.url.endsWith('/login') || apiResponse.url.endsWith('/ent/select')) { throw new Error('Cannot authenticate Enterprise Search user'); } diff --git a/x-pack/plugins/enterprise_search/server/plugin.ts b/x-pack/plugins/enterprise_search/server/plugin.ts index 617210a54426..729a03d24065 100644 --- a/x-pack/plugins/enterprise_search/server/plugin.ts +++ b/x-pack/plugins/enterprise_search/server/plugin.ts @@ -31,8 +31,10 @@ import { IEnterpriseSearchRequestHandler, } from './lib/enterprise_search_request_handler'; -import { registerConfigDataRoute } from './routes/enterprise_search/config_data'; +import { enterpriseSearchTelemetryType } from './saved_objects/enterprise_search/telemetry'; +import { registerTelemetryUsageCollector as registerESTelemetryUsageCollector } from './collectors/enterprise_search/telemetry'; import { registerTelemetryRoute } from './routes/enterprise_search/telemetry'; +import { registerConfigDataRoute } from './routes/enterprise_search/config_data'; import { appSearchTelemetryType } from './saved_objects/app_search/telemetry'; import { registerTelemetryUsageCollector as registerASTelemetryUsageCollector } from './collectors/app_search/telemetry'; @@ -81,8 +83,12 @@ export class EnterpriseSearchPlugin implements Plugin { name: ENTERPRISE_SEARCH_PLUGIN.NAME, order: 0, icon: 'logoEnterpriseSearch', - navLinkId: APP_SEARCH_PLUGIN.ID, // TODO - remove this once functional tests no longer rely on navLinkId - app: ['kibana', APP_SEARCH_PLUGIN.ID, WORKPLACE_SEARCH_PLUGIN.ID], + app: [ + 'kibana', + ENTERPRISE_SEARCH_PLUGIN.ID, + APP_SEARCH_PLUGIN.ID, + WORKPLACE_SEARCH_PLUGIN.ID, + ], catalogue: [ENTERPRISE_SEARCH_PLUGIN.ID, APP_SEARCH_PLUGIN.ID, WORKPLACE_SEARCH_PLUGIN.ID], privileges: null, }); @@ -94,14 +100,16 @@ export class EnterpriseSearchPlugin implements Plugin { const dependencies = { config, security, request, log }; const { hasAppSearchAccess, hasWorkplaceSearchAccess } = await checkAccess(dependencies); + const showEnterpriseSearchOverview = hasAppSearchAccess || hasWorkplaceSearchAccess; return { navLinks: { + enterpriseSearch: showEnterpriseSearchOverview, appSearch: hasAppSearchAccess, workplaceSearch: hasWorkplaceSearchAccess, }, catalogue: { - enterpriseSearch: hasAppSearchAccess || hasWorkplaceSearchAccess, + enterpriseSearch: showEnterpriseSearchOverview, appSearch: hasAppSearchAccess, workplaceSearch: hasWorkplaceSearchAccess, }, @@ -123,6 +131,7 @@ export class EnterpriseSearchPlugin implements Plugin { /** * Bootstrap the routes, saved objects, and collector for telemetry */ + savedObjects.registerType(enterpriseSearchTelemetryType); savedObjects.registerType(appSearchTelemetryType); savedObjects.registerType(workplaceSearchTelemetryType); let savedObjectsStarted: SavedObjectsServiceStart; @@ -131,6 +140,7 @@ export class EnterpriseSearchPlugin implements Plugin { savedObjectsStarted = coreStart.savedObjects; if (usageCollection) { + registerESTelemetryUsageCollector(usageCollection, savedObjectsStarted, this.logger); registerASTelemetryUsageCollector(usageCollection, savedObjectsStarted, this.logger); registerWSTelemetryUsageCollector(usageCollection, savedObjectsStarted, this.logger); } diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/telemetry.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/telemetry.ts index 7ed1d7b17753..bfc07c8b64ef 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/telemetry.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/telemetry.ts @@ -9,12 +9,13 @@ import { schema } from '@kbn/config-schema'; import { IRouteDependencies } from '../../plugin'; import { incrementUICounter } from '../../collectors/lib/telemetry'; +import { ES_TELEMETRY_NAME } from '../../collectors/enterprise_search/telemetry'; import { AS_TELEMETRY_NAME } from '../../collectors/app_search/telemetry'; import { WS_TELEMETRY_NAME } from '../../collectors/workplace_search/telemetry'; const productToTelemetryMap = { + enterprise_search: ES_TELEMETRY_NAME, app_search: AS_TELEMETRY_NAME, workplace_search: WS_TELEMETRY_NAME, - enterprise_search: 'TODO', }; export function registerTelemetryRoute({ diff --git a/x-pack/plugins/enterprise_search/server/saved_objects/enterprise_search/telemetry.ts b/x-pack/plugins/enterprise_search/server/saved_objects/enterprise_search/telemetry.ts new file mode 100644 index 000000000000..54044e67939d --- /dev/null +++ b/x-pack/plugins/enterprise_search/server/saved_objects/enterprise_search/telemetry.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +/* istanbul ignore file */ + +import { SavedObjectsType } from 'src/core/server'; +import { ES_TELEMETRY_NAME } from '../../collectors/enterprise_search/telemetry'; + +export const enterpriseSearchTelemetryType: SavedObjectsType = { + name: ES_TELEMETRY_NAME, + hidden: false, + namespaceType: 'agnostic', + mappings: { + dynamic: false, + properties: {}, + }, +}; diff --git a/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap b/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap index e4014cf49778..63a59d59d6d0 100644 --- a/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap +++ b/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap @@ -111,6 +111,7 @@ Array [ "visualization", "timelion-sheet", "canvas-workpad", + "lens", "map", "dashboard", "query", diff --git a/x-pack/plugins/features/server/oss_features.ts b/x-pack/plugins/features/server/oss_features.ts index e37c7491de5d..4122c590e74b 100644 --- a/x-pack/plugins/features/server/oss_features.ts +++ b/x-pack/plugins/features/server/oss_features.ts @@ -172,6 +172,7 @@ export const buildOSSFeatures = ({ savedObjectTypes, includeTimelion }: BuildOSS 'visualization', 'timelion-sheet', 'canvas-workpad', + 'lens', 'map', 'dashboard', 'query', diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_allocation.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_allocation.tsx index 6f80afccbff5..6a22d8716514 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_allocation.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_allocation.tsx @@ -52,7 +52,7 @@ export const NodeAllocation = ({ phaseData, isShowingErrors, }: React.PropsWithChildren>) => { - const { isLoading, data: nodes, error, sendRequest } = useLoadNodes(); + const { isLoading, data: nodes, error, resendRequest } = useLoadNodes(); const [selectedNodeAttrsForDetails, setSelectedNodeAttrsForDetails] = useState( null @@ -84,7 +84,7 @@ export const NodeAllocation = ({

{message} ({statusCode})

- + = ({ close, selectedNodeAttrs }) => { - const { data, isLoading, error, sendRequest } = useLoadNodeDetails(selectedNodeAttrs); + const { data, isLoading, error, resendRequest } = useLoadNodeDetails(selectedNodeAttrs); let content; if (isLoading) { content = ; @@ -47,7 +47,7 @@ export const NodeAttrsDetails: React.FunctionComponent = ({ close, select

{message} ({statusCode})

- + = ({ onChange, getUrlForApp, }) => { - const { error, isLoading, data, sendRequest } = useLoadSnapshotPolicies(); + const { error, isLoading, data, resendRequest } = useLoadSnapshotPolicies(); const policies = data.map((name: string) => ({ label: name, @@ -75,7 +75,7 @@ export const SnapshotPolicies: React.FunctionComponent = ({ { - const { error, isLoading, data: policies, sendRequest } = useLoadPoliciesList(false); + const { error, isLoading, data: policies, resendRequest } = useLoadPoliciesList(false); if (isLoading) { return ( } actions={ - + = navigateToApp, history, }) => { - const { data: policies, isLoading, error, sendRequest } = useLoadPoliciesList(true); + const { data: policies, isLoading, error, resendRequest } = useLoadPoliciesList(true); if (isLoading) { return ( @@ -53,7 +53,7 @@ export const PolicyTable: React.FunctionComponent =

} actions={ - + = policies={policies || []} history={history} navigateToApp={navigateToApp} - updatePolicies={sendRequest} + updatePolicies={resendRequest} /> ); }; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list.tsx index 8ba7409a9ac5..05f7f53969de 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list.tsx @@ -42,7 +42,7 @@ export const ComponentTemplateList: React.FunctionComponent = ({ } = useGlobalFlyout(); const { api, trackMetric, documentation } = useComponentTemplatesContext(); - const { data, isLoading, error, sendRequest } = api.useLoadComponentTemplates(); + const { data, isLoading, error, resendRequest } = api.useLoadComponentTemplates(); const [componentTemplatesToDelete, setComponentTemplatesToDelete] = useState([]); @@ -170,7 +170,7 @@ export const ComponentTemplateList: React.FunctionComponent = ({ = ({ } else if (data && data.length === 0) { content = ; } else if (error) { - content = ; + content = ; } return ( @@ -194,7 +194,7 @@ export const ComponentTemplateList: React.FunctionComponent = ({ callback={(deleteResponse) => { if (deleteResponse?.hasDeletedComponentTemplates) { // refetch the component templates - sendRequest(); + resendRequest(); // go back to list view (if deleted from details flyout) goToComponentTemplateList(); } diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/types/document_fields.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/types/document_fields.ts index a9f6d2ea03bd..6882ddea4ad5 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/types/document_fields.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/types/document_fields.ts @@ -24,7 +24,7 @@ export interface DataTypeDefinition { export interface ParameterDefinition { title?: string; description?: JSX.Element | string; - fieldConfig: FieldConfig; + fieldConfig: FieldConfig; schema?: any; props?: { [key: string]: ParameterDefinition }; documentation?: { diff --git a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx index d37576f18e84..4f2a5c4a27b7 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx @@ -49,7 +49,7 @@ export const DataStreamList: React.FunctionComponent {}; + reload: UseRequestResponse['resendRequest']; history: ScopedHistory; includeStats: boolean; filters?: string; diff --git a/x-pack/plugins/index_management/public/application/sections/home/template_list/legacy_templates/template_table/template_table.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/legacy_templates/template_table/template_table.tsx index 9203e76fce78..7ec6f1f94a2a 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/template_list/legacy_templates/template_table/template_table.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/template_list/legacy_templates/template_table/template_table.tsx @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { EuiInMemoryTable, EuiButton, EuiLink, EuiBasicTableColumn } from '@elastic/eui'; import { ScopedHistory } from 'kibana/public'; -import { SendRequestResponse, reactRouterNavigate } from '../../../../../../shared_imports'; +import { UseRequestResponse, reactRouterNavigate } from '../../../../../../shared_imports'; import { TemplateListItem } from '../../../../../../../common'; import { UIM_TEMPLATE_SHOW_DETAILS_CLICK } from '../../../../../../../common/constants'; import { TemplateDeleteModal } from '../../../../../components'; @@ -20,7 +20,7 @@ import { TemplateTypeIndicator } from '../../components'; interface Props { templates: TemplateListItem[]; - reload: () => Promise; + reload: UseRequestResponse['resendRequest']; editTemplate: (name: string, isLegacy?: boolean) => void; cloneTemplate: (name: string, isLegacy?: boolean) => void; history: ScopedHistory; diff --git a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/template_details_content.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/template_details_content.tsx index 5bacffc4c240..94891297c857 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/template_details_content.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_details/template_details_content.tsx @@ -31,7 +31,7 @@ import { UIM_TEMPLATE_DETAIL_PANEL_ALIASES_TAB, UIM_TEMPLATE_DETAIL_PANEL_PREVIEW_TAB, } from '../../../../../../common/constants'; -import { SendRequestResponse } from '../../../../../shared_imports'; +import { UseRequestResponse } from '../../../../../shared_imports'; import { TemplateDeleteModal, SectionLoading, SectionError, Error } from '../../../../components'; import { useLoadIndexTemplate } from '../../../../services/api'; import { decodePathFromReactRouter } from '../../../../services/routing'; @@ -92,7 +92,7 @@ export interface Props { onClose: () => void; editTemplate: (name: string, isLegacy?: boolean) => void; cloneTemplate: (name: string, isLegacy?: boolean) => void; - reload: () => Promise; + reload: UseRequestResponse['resendRequest']; } export const TemplateDetailsContent = ({ diff --git a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_list.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_list.tsx index f421bc5d87a5..c711f457123f 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_list.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_list.tsx @@ -59,7 +59,7 @@ export const TemplateList: React.FunctionComponent { const { uiMetricService } = useServices(); - const { error, isLoading, data: allTemplates, sendRequest: reload } = useLoadIndexTemplates(); + const { error, isLoading, data: allTemplates, resendRequest: reload } = useLoadIndexTemplates(); const [filters, setFilters] = useState>({ managed: { diff --git a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_table/template_table.tsx b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_table/template_table.tsx index 3dffdcde160f..c32fd29cf9f9 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/template_list/template_table/template_table.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/template_list/template_table/template_table.tsx @@ -12,7 +12,7 @@ import { ScopedHistory } from 'kibana/public'; import { TemplateListItem } from '../../../../../../common'; import { UIM_TEMPLATE_SHOW_DETAILS_CLICK } from '../../../../../../common/constants'; -import { SendRequestResponse, reactRouterNavigate } from '../../../../../shared_imports'; +import { UseRequestResponse, reactRouterNavigate } from '../../../../../shared_imports'; import { encodePathForReactRouter } from '../../../../services/routing'; import { useServices } from '../../../../app_context'; import { TemplateDeleteModal } from '../../../../components'; @@ -21,7 +21,7 @@ import { TemplateTypeIndicator } from '../components'; interface Props { templates: TemplateListItem[]; - reload: () => Promise; + reload: UseRequestResponse['resendRequest']; editTemplate: (name: string) => void; cloneTemplate: (name: string) => void; history: ScopedHistory; diff --git a/x-pack/plugins/index_management/public/shared_imports.ts b/x-pack/plugins/index_management/public/shared_imports.ts index f7f992a09050..d58545768732 100644 --- a/x-pack/plugins/index_management/public/shared_imports.ts +++ b/x-pack/plugins/index_management/public/shared_imports.ts @@ -8,6 +8,7 @@ export { SendRequestConfig, SendRequestResponse, UseRequestConfig, + UseRequestResponse, sendRequest, useRequest, Forms, diff --git a/x-pack/plugins/infra/common/http_api/index.ts b/x-pack/plugins/infra/common/http_api/index.ts index 818009417fb1..4c729d11ba8c 100644 --- a/x-pack/plugins/infra/common/http_api/index.ts +++ b/x-pack/plugins/infra/common/http_api/index.ts @@ -10,3 +10,4 @@ export * from './log_entries'; export * from './metrics_explorer'; export * from './metrics_api'; export * from './log_alerts'; +export * from './snapshot_api'; diff --git a/x-pack/plugins/infra/common/http_api/metrics_api.ts b/x-pack/plugins/infra/common/http_api/metrics_api.ts index 7436566f039c..41657fdce215 100644 --- a/x-pack/plugins/infra/common/http_api/metrics_api.ts +++ b/x-pack/plugins/infra/common/http_api/metrics_api.ts @@ -33,7 +33,6 @@ export const MetricsAPIRequestRT = rt.intersection([ afterKey: rt.union([rt.null, afterKeyObjectRT]), limit: rt.union([rt.number, rt.null, rt.undefined]), filters: rt.array(rt.object), - forceInterval: rt.boolean, dropLastBucket: rt.boolean, alignDataToEnd: rt.boolean, }), @@ -59,7 +58,10 @@ export const MetricsAPIRowRT = rt.intersection([ rt.type({ timestamp: rt.number, }), - rt.record(rt.string, rt.union([rt.string, rt.number, rt.null, rt.undefined])), + rt.record( + rt.string, + rt.union([rt.string, rt.number, rt.null, rt.undefined, rt.array(rt.object)]) + ), ]); export const MetricsAPISeriesRT = rt.intersection([ diff --git a/x-pack/plugins/infra/common/http_api/metrics_explorer.ts b/x-pack/plugins/infra/common/http_api/metrics_explorer.ts index c5776e0b0ced..460b2bf9d802 100644 --- a/x-pack/plugins/infra/common/http_api/metrics_explorer.ts +++ b/x-pack/plugins/infra/common/http_api/metrics_explorer.ts @@ -89,7 +89,10 @@ export const metricsExplorerRowRT = rt.intersection([ rt.type({ timestamp: rt.number, }), - rt.record(rt.string, rt.union([rt.string, rt.number, rt.null, rt.undefined])), + rt.record( + rt.string, + rt.union([rt.string, rt.number, rt.null, rt.undefined, rt.array(rt.object)]) + ), ]); export const metricsExplorerSeriesRT = rt.intersection([ diff --git a/x-pack/plugins/infra/common/http_api/snapshot_api.ts b/x-pack/plugins/infra/common/http_api/snapshot_api.ts index 11cb57238f91..e1b8dfa4770b 100644 --- a/x-pack/plugins/infra/common/http_api/snapshot_api.ts +++ b/x-pack/plugins/infra/common/http_api/snapshot_api.ts @@ -6,7 +6,7 @@ import * as rt from 'io-ts'; import { SnapshotMetricTypeRT, ItemTypeRT } from '../inventory_models/types'; -import { metricsExplorerSeriesRT } from './metrics_explorer'; +import { MetricsAPISeriesRT } from './metrics_api'; export const SnapshotNodePathRT = rt.intersection([ rt.type({ @@ -22,7 +22,7 @@ const SnapshotNodeMetricOptionalRT = rt.partial({ value: rt.union([rt.number, rt.null]), avg: rt.union([rt.number, rt.null]), max: rt.union([rt.number, rt.null]), - timeseries: metricsExplorerSeriesRT, + timeseries: MetricsAPISeriesRT, }); const SnapshotNodeMetricRequiredRT = rt.type({ @@ -36,6 +36,7 @@ export const SnapshotNodeMetricRT = rt.intersection([ export const SnapshotNodeRT = rt.type({ metrics: rt.array(SnapshotNodeMetricRT), path: rt.array(SnapshotNodePathRT), + name: rt.string, }); export const SnapshotNodeResponseRT = rt.type({ diff --git a/x-pack/plugins/infra/common/inventory_models/types.ts b/x-pack/plugins/infra/common/inventory_models/types.ts index 570220bbc7aa..851646ef1fa1 100644 --- a/x-pack/plugins/infra/common/inventory_models/types.ts +++ b/x-pack/plugins/infra/common/inventory_models/types.ts @@ -281,6 +281,10 @@ export const ESSumBucketAggRT = rt.type({ }), }); +export const ESTopHitsAggRT = rt.type({ + top_hits: rt.object, +}); + interface SnapshotTermsWithAggregation { terms: { field: string }; aggregations: MetricsUIAggregation; @@ -304,6 +308,7 @@ export const ESAggregationRT = rt.union([ ESSumBucketAggRT, ESTermsWithAggregationRT, ESCaridnalityAggRT, + ESTopHitsAggRT, ]); export const MetricsUIAggregationRT = rt.record(rt.string, ESAggregationRT); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx index d2c30a4f38ee..e01ca3ab6e84 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx @@ -88,6 +88,7 @@ describe('ConditionalToolTip', () => { mockedUseSnapshot.mockReturnValue({ nodes: [ { + name: 'host-01', path: [{ label: 'host-01', value: 'host-01', ip: '192.168.1.10' }], metrics: [ { name: 'cpu', value: 0.1, avg: 0.4, max: 0.7 }, diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/calculate_bounds_from_nodes.test.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/calculate_bounds_from_nodes.test.ts index fbb6aa933219..49f4b5653293 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/calculate_bounds_from_nodes.test.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/calculate_bounds_from_nodes.test.ts @@ -7,6 +7,7 @@ import { calculateBoundsFromNodes } from './calculate_bounds_from_nodes'; import { SnapshotNode } from '../../../../../common/http_api/snapshot_api'; const nodes: SnapshotNode[] = [ { + name: 'host-01', path: [{ value: 'host-01', label: 'host-01' }], metrics: [ { @@ -18,6 +19,7 @@ const nodes: SnapshotNode[] = [ ], }, { + name: 'host-02', path: [{ value: 'host-02', label: 'host-02' }], metrics: [ { diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/sort_nodes.test.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/sort_nodes.test.ts index 2a9f8b911c12..f7d9f029f00d 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/sort_nodes.test.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/sort_nodes.test.ts @@ -9,6 +9,7 @@ import { SnapshotNode } from '../../../../../common/http_api/snapshot_api'; const nodes: SnapshotNode[] = [ { + name: 'host-01', path: [{ value: 'host-01', label: 'host-01' }], metrics: [ { @@ -20,6 +21,7 @@ const nodes: SnapshotNode[] = [ ], }, { + name: 'host-02', path: [{ value: 'host-02', label: 'host-02' }], metrics: [ { diff --git a/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts index 939498305eb9..c5b667fb2053 100644 --- a/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/log_entries/kibana_log_entries_adapter.ts @@ -8,12 +8,12 @@ import { timeMilliseconds } from 'd3-time'; import * as runtimeTypes from 'io-ts'; -import { compact, first, get, has } from 'lodash'; +import { compact, first } from 'lodash'; import { pipe } from 'fp-ts/lib/pipeable'; import { map, fold } from 'fp-ts/lib/Either'; import { identity, constant } from 'fp-ts/lib/function'; import { RequestHandlerContext } from 'src/core/server'; -import { JsonObject, JsonValue } from '../../../../common/typed_json'; +import { JsonValue } from '../../../../common/typed_json'; import { LogEntriesAdapter, LogEntriesParams, @@ -31,7 +31,7 @@ const TIMESTAMP_FORMAT = 'epoch_millis'; interface LogItemHit { _index: string; _id: string; - _source: JsonObject; + fields: { [key: string]: [value: unknown] }; sort: [number, number]; } @@ -82,7 +82,8 @@ export class InfraKibanaLogEntriesAdapter implements LogEntriesAdapter { body: { size: typeof size !== 'undefined' ? size : LOG_ENTRIES_PAGE_SIZE, track_total_hits: false, - _source: fields, + _source: false, + fields, query: { bool: { filter: [ @@ -214,6 +215,8 @@ export class InfraKibanaLogEntriesAdapter implements LogEntriesAdapter { values: [id], }, }, + fields: ['*'], + _source: false, }, }; @@ -230,8 +233,8 @@ function mapHitsToLogEntryDocuments(hits: SortedSearchHit[], fields: string[]): return hits.map((hit) => { const logFields = fields.reduce<{ [fieldName: string]: JsonValue }>( (flattenedFields, field) => { - if (has(hit._source, field)) { - flattenedFields[field] = get(hit._source, field); + if (field in hit.fields) { + flattenedFields[field] = hit.fields[field][0]; } return flattenedFields; }, diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts index 2f3593a11f66..d6592719d072 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts @@ -16,12 +16,11 @@ import { } from '../../adapters/framework/adapter_types'; import { Comparator, InventoryMetricConditions } from './types'; import { AlertServices } from '../../../../../alerts/server'; -import { InfraSnapshot } from '../../snapshot'; -import { parseFilterQuery } from '../../../utils/serialized_query'; import { InventoryItemType, SnapshotMetricType } from '../../../../common/inventory_models/types'; -import { InfraTimerangeInput } from '../../../../common/http_api/snapshot_api'; -import { InfraSourceConfiguration } from '../../sources'; +import { InfraTimerangeInput, SnapshotRequest } from '../../../../common/http_api/snapshot_api'; +import { InfraSource } from '../../sources'; import { UNGROUPED_FACTORY_KEY } from '../common/utils'; +import { getNodes } from '../../../routes/snapshot/lib/get_nodes'; type ConditionResult = InventoryMetricConditions & { shouldFire: boolean[]; @@ -33,7 +32,7 @@ type ConditionResult = InventoryMetricConditions & { export const evaluateCondition = async ( condition: InventoryMetricConditions, nodeType: InventoryItemType, - sourceConfiguration: InfraSourceConfiguration, + source: InfraSource, callCluster: AlertServices['callCluster'], filterQuery?: string, lookbackSize?: number @@ -55,7 +54,7 @@ export const evaluateCondition = async ( nodeType, metric, timerange, - sourceConfiguration, + source, filterQuery, customMetric ); @@ -94,12 +93,11 @@ const getData = async ( nodeType: InventoryItemType, metric: SnapshotMetricType, timerange: InfraTimerangeInput, - sourceConfiguration: InfraSourceConfiguration, + source: InfraSource, filterQuery?: string, customMetric?: SnapshotCustomMetricInput ) => { - const snapshot = new InfraSnapshot(); - const esClient = ( + const client = ( options: CallWithRequestParams ): Promise> => callCluster('search', options); @@ -107,17 +105,17 @@ const getData = async ( metric === 'custom' ? (customMetric as SnapshotCustomMetricInput) : { type: metric }, ]; - const options = { - filterQuery: parseFilterQuery(filterQuery), + const snapshotRequest: SnapshotRequest = { + filterQuery, nodeType, groupBy: [], - sourceConfiguration, + sourceId: 'default', metrics, timerange, includeTimeseries: Boolean(timerange.lookbackSize), }; try { - const { nodes } = await snapshot.getNodes(esClient, options); + const { nodes } = await getNodes(client, snapshotRequest, source); if (!nodes.length) return { [UNGROUPED_FACTORY_KEY]: null }; // No Data state diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts index bdac9dcd1dee..99904f15b460 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts @@ -50,9 +50,7 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) = ); const results = await Promise.all( - criteria.map((c) => - evaluateCondition(c, nodeType, source.configuration, services.callCluster, filterQuery) - ) + criteria.map((c) => evaluateCondition(c, nodeType, source, services.callCluster, filterQuery)) ); const inventoryItems = Object.keys(first(results)!); diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/preview_inventory_metric_threshold_alert.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/preview_inventory_metric_threshold_alert.ts index 755c395818f5..2ab015b6b37a 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/preview_inventory_metric_threshold_alert.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/preview_inventory_metric_threshold_alert.ts @@ -26,7 +26,7 @@ interface InventoryMetricThresholdParams { interface PreviewInventoryMetricThresholdAlertParams { callCluster: ILegacyScopedClusterClient['callAsCurrentUser']; params: InventoryMetricThresholdParams; - config: InfraSource['configuration']; + source: InfraSource; lookback: Unit; alertInterval: string; } @@ -34,7 +34,7 @@ interface PreviewInventoryMetricThresholdAlertParams { export const previewInventoryMetricThresholdAlert = async ({ callCluster, params, - config, + source, lookback, alertInterval, }: PreviewInventoryMetricThresholdAlertParams) => { @@ -55,7 +55,7 @@ export const previewInventoryMetricThresholdAlert = async ({ try { const results = await Promise.all( criteria.map((c) => - evaluateCondition(c, nodeType, config, callCluster, filterQuery, lookbackSize) + evaluateCondition(c, nodeType, source, callCluster, filterQuery, lookbackSize) ) ); diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/metric_query.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/metric_query.ts index 078ca46d42e6..8696081043ff 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/metric_query.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/metric_query.ts @@ -8,8 +8,8 @@ import { networkTraffic } from '../../../../../common/inventory_models/shared/me import { MetricExpressionParams, Aggregators } from '../types'; import { getIntervalInSeconds } from '../../../../utils/get_interval_in_seconds'; import { roundTimestamp } from '../../../../utils/round_timestamp'; -import { getDateHistogramOffset } from '../../../snapshot/query_helpers'; import { createPercentileAggregation } from './create_percentile_aggregation'; +import { calculateDateHistogramOffset } from '../../../metrics/lib/calculate_date_histogram_offset'; const MINIMUM_BUCKETS = 5; @@ -46,7 +46,7 @@ export const getElasticsearchMetricQuery = ( timeUnit ); - const offset = getDateHistogramOffset(from, interval); + const offset = calculateDateHistogramOffset({ from, to, interval, field: timefield }); const aggregations = aggType === Aggregators.COUNT diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.ts index 099e7c3b5038..7c8560d72ff9 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/convert_document_source_to_log_item_fields.ts @@ -20,6 +20,11 @@ const serializeValue = (value: any): string => { } return `${value}`; }; +export const convertESFieldsToLogItemFields = (fields: { + [field: string]: [value: unknown]; +}): LogEntriesItemField[] => { + return Object.keys(fields).map((field) => ({ field, value: serializeValue(fields[field][0]) })); +}; export const convertDocumentSourceToLogItemFields = ( source: JsonObject, diff --git a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts index 9b3e31f4da87..e211f72b4e07 100644 --- a/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts +++ b/x-pack/plugins/infra/server/lib/domains/log_entries_domain/log_entries_domain.ts @@ -22,7 +22,7 @@ import { SavedSourceConfigurationFieldColumnRuntimeType, } from '../../sources'; import { getBuiltinRules } from './builtin_rules'; -import { convertDocumentSourceToLogItemFields } from './convert_document_source_to_log_item_fields'; +import { convertESFieldsToLogItemFields } from './convert_document_source_to_log_item_fields'; import { CompiledLogMessageFormattingRule, Fields, @@ -264,7 +264,7 @@ export class InfraLogEntriesDomain { tiebreaker: document.sort[1], }, fields: sortBy( - [...defaultFields, ...convertDocumentSourceToLogItemFields(document._source)], + [...defaultFields, ...convertESFieldsToLogItemFields(document.fields)], 'field' ), }; @@ -313,7 +313,7 @@ export class InfraLogEntriesDomain { interface LogItemHit { _index: string; _id: string; - _source: JsonObject; + fields: { [field: string]: [value: unknown] }; sort: [number, number]; } diff --git a/x-pack/plugins/infra/server/lib/infra_types.ts b/x-pack/plugins/infra/server/lib/infra_types.ts index 9896ad6ac1cd..084ece52302b 100644 --- a/x-pack/plugins/infra/server/lib/infra_types.ts +++ b/x-pack/plugins/infra/server/lib/infra_types.ts @@ -8,7 +8,6 @@ import { InfraSourceConfiguration } from '../../common/graphql/types'; import { InfraFieldsDomain } from './domains/fields_domain'; import { InfraLogEntriesDomain } from './domains/log_entries_domain'; import { InfraMetricsDomain } from './domains/metrics_domain'; -import { InfraSnapshot } from './snapshot'; import { InfraSources } from './sources'; import { InfraSourceStatus } from './source_status'; import { InfraConfig } from '../plugin'; @@ -30,7 +29,6 @@ export interface InfraDomainLibs { export interface InfraBackendLibs extends InfraDomainLibs { configuration: InfraConfig; framework: KibanaFramework; - snapshot: InfraSnapshot; sources: InfraSources; sourceStatus: InfraSourceStatus; } diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/create_aggregations.test.ts.snap b/x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/create_aggregations.test.ts.snap index d2d90914eced..2cbbc623aed3 100644 --- a/x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/create_aggregations.test.ts.snap +++ b/x-pack/plugins/infra/server/lib/metrics/lib/__snapshots__/create_aggregations.test.ts.snap @@ -53,7 +53,6 @@ Object { "groupBy0": Object { "terms": Object { "field": "host.name", - "order": "asc", }, }, }, diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/convert_histogram_buckets_to_timeseries.ts b/x-pack/plugins/infra/server/lib/metrics/lib/convert_histogram_buckets_to_timeseries.ts index 95e6ece21513..90e584368e9a 100644 --- a/x-pack/plugins/infra/server/lib/metrics/lib/convert_histogram_buckets_to_timeseries.ts +++ b/x-pack/plugins/infra/server/lib/metrics/lib/convert_histogram_buckets_to_timeseries.ts @@ -5,6 +5,7 @@ */ import { get, values, first } from 'lodash'; +import * as rt from 'io-ts'; import { MetricsAPIRequest, MetricsAPISeries, @@ -13,15 +14,20 @@ import { } from '../../../../common/http_api/metrics_api'; import { HistogramBucket, - MetricValueType, BasicMetricValueRT, NormalizedMetricValueRT, PercentilesTypeRT, PercentilesKeyedTypeRT, + TopHitsTypeRT, + MetricValueTypeRT, } from '../types'; + const BASE_COLUMNS = [{ name: 'timestamp', type: 'date' }] as MetricsAPIColumn[]; -const getValue = (valueObject: string | number | MetricValueType) => { +const ValueObjectTypeRT = rt.union([rt.string, rt.number, MetricValueTypeRT]); +type ValueObjectType = rt.TypeOf; + +const getValue = (valueObject: ValueObjectType) => { if (NormalizedMetricValueRT.is(valueObject)) { return valueObject.normalized_value || valueObject.value; } @@ -50,6 +56,10 @@ const getValue = (valueObject: string | number | MetricValueType) => { return valueObject.value; } + if (TopHitsTypeRT.is(valueObject)) { + return valueObject.hits.hits.map((hit) => hit._source); + } + return null; }; @@ -61,8 +71,8 @@ const convertBucketsToRows = ( const ids = options.metrics.map((metric) => metric.id); const metrics = ids.reduce((acc, id) => { const valueObject = get(bucket, [id]); - return { ...acc, [id]: getValue(valueObject) }; - }, {} as Record); + return { ...acc, [id]: ValueObjectTypeRT.is(valueObject) ? getValue(valueObject) : null }; + }, {} as Record); return { timestamp: bucket.key as number, ...metrics }; }); }; diff --git a/x-pack/plugins/infra/server/lib/metrics/lib/create_aggregations.ts b/x-pack/plugins/infra/server/lib/metrics/lib/create_aggregations.ts index 991e5febfc63..63fdbb3d2b30 100644 --- a/x-pack/plugins/infra/server/lib/metrics/lib/create_aggregations.ts +++ b/x-pack/plugins/infra/server/lib/metrics/lib/create_aggregations.ts @@ -33,7 +33,7 @@ export const createAggregations = (options: MetricsAPIRequest) => { composite: { size: limit, sources: options.groupBy.map((field, index) => ({ - [`groupBy${index}`]: { terms: { field, order: 'asc' } }, + [`groupBy${index}`]: { terms: { field } }, })), }, aggs: histogramAggregation, diff --git a/x-pack/plugins/infra/server/lib/metrics/types.ts b/x-pack/plugins/infra/server/lib/metrics/types.ts index d1866470e0cf..8746614b559d 100644 --- a/x-pack/plugins/infra/server/lib/metrics/types.ts +++ b/x-pack/plugins/infra/server/lib/metrics/types.ts @@ -25,17 +25,51 @@ export const PercentilesKeyedTypeRT = rt.type({ values: rt.array(rt.type({ key: rt.string, value: NumberOrNullRT })), }); +export const TopHitsTypeRT = rt.type({ + hits: rt.type({ + total: rt.type({ + value: rt.number, + relation: rt.string, + }), + hits: rt.array( + rt.intersection([ + rt.type({ + _index: rt.string, + _id: rt.string, + _score: NumberOrNullRT, + _source: rt.object, + }), + rt.partial({ + sort: rt.array(rt.union([rt.string, rt.number])), + max_score: NumberOrNullRT, + }), + ]) + ), + }), +}); + export const MetricValueTypeRT = rt.union([ BasicMetricValueRT, NormalizedMetricValueRT, PercentilesTypeRT, PercentilesKeyedTypeRT, + TopHitsTypeRT, ]); export type MetricValueType = rt.TypeOf; +export const TermsWithMetrics = rt.intersection([ + rt.type({ + buckets: rt.array(rt.record(rt.string, rt.union([rt.number, rt.string, MetricValueTypeRT]))), + }), + rt.partial({ + sum_other_doc_count: rt.number, + doc_count_error_upper_bound: rt.number, + }), +]); + export const HistogramBucketRT = rt.record( rt.string, - rt.union([rt.number, rt.string, MetricValueTypeRT]) + rt.union([rt.number, rt.string, MetricValueTypeRT, TermsWithMetrics]) ); export const HistogramResponseRT = rt.type({ diff --git a/x-pack/plugins/infra/server/lib/snapshot/query_helpers.ts b/x-pack/plugins/infra/server/lib/snapshot/query_helpers.ts deleted file mode 100644 index ca63043ba868..000000000000 --- a/x-pack/plugins/infra/server/lib/snapshot/query_helpers.ts +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -import { findInventoryModel, findInventoryFields } from '../../../common/inventory_models/index'; -import { InfraSnapshotRequestOptions } from './types'; -import { getIntervalInSeconds } from '../../utils/get_interval_in_seconds'; -import { - MetricsUIAggregation, - MetricsUIAggregationRT, - InventoryItemType, -} from '../../../common/inventory_models/types'; -import { - SnapshotMetricInput, - SnapshotCustomMetricInputRT, -} from '../../../common/http_api/snapshot_api'; -import { networkTraffic } from '../../../common/inventory_models/shared/metrics/snapshot/network_traffic'; - -interface GroupBySource { - [id: string]: { - terms: { - field: string | null | undefined; - missing_bucket?: boolean; - }; - }; -} - -export const getFieldByNodeType = (options: InfraSnapshotRequestOptions) => { - const inventoryFields = findInventoryFields(options.nodeType, options.sourceConfiguration.fields); - return inventoryFields.id; -}; - -export const getGroupedNodesSources = (options: InfraSnapshotRequestOptions) => { - const fields = findInventoryFields(options.nodeType, options.sourceConfiguration.fields); - const sources: GroupBySource[] = options.groupBy.map((gb) => { - return { [`${gb.field}`]: { terms: { field: gb.field } } }; - }); - sources.push({ - id: { - terms: { field: fields.id }, - }, - }); - sources.push({ - name: { terms: { field: fields.name, missing_bucket: true } }, - }); - return sources; -}; - -export const getMetricsSources = (options: InfraSnapshotRequestOptions) => { - const fields = findInventoryFields(options.nodeType, options.sourceConfiguration.fields); - return [{ id: { terms: { field: fields.id } } }]; -}; - -export const metricToAggregation = ( - nodeType: InventoryItemType, - metric: SnapshotMetricInput, - index: number -) => { - const inventoryModel = findInventoryModel(nodeType); - if (SnapshotCustomMetricInputRT.is(metric)) { - if (metric.aggregation === 'rate') { - return networkTraffic(`custom_${index}`, metric.field); - } - return { - [`custom_${index}`]: { - [metric.aggregation]: { - field: metric.field, - }, - }, - }; - } - return inventoryModel.metrics.snapshot?.[metric.type]; -}; - -export const getMetricsAggregations = ( - options: InfraSnapshotRequestOptions -): MetricsUIAggregation => { - const { metrics } = options; - return metrics.reduce((aggs, metric, index) => { - const aggregation = metricToAggregation(options.nodeType, metric, index); - if (!MetricsUIAggregationRT.is(aggregation)) { - throw new Error( - i18n.translate('xpack.infra.snapshot.missingSnapshotMetricError', { - defaultMessage: 'The aggregation for {metric} for {nodeType} is not available.', - values: { - nodeType: options.nodeType, - metric: metric.type, - }, - }) - ); - } - return { ...aggs, ...aggregation }; - }, {}); -}; - -export const getDateHistogramOffset = (from: number, interval: string): string => { - const fromInSeconds = Math.floor(from / 1000); - const bucketSizeInSeconds = getIntervalInSeconds(interval); - - // negative offset to align buckets with full intervals (e.g. minutes) - const offset = (fromInSeconds % bucketSizeInSeconds) - bucketSizeInSeconds; - return `${offset}s`; -}; diff --git a/x-pack/plugins/infra/server/lib/snapshot/response_helpers.test.ts b/x-pack/plugins/infra/server/lib/snapshot/response_helpers.test.ts deleted file mode 100644 index 74840afc157d..000000000000 --- a/x-pack/plugins/infra/server/lib/snapshot/response_helpers.test.ts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { - isIPv4, - getIPFromBucket, - InfraSnapshotNodeGroupByBucket, - getMetricValueFromBucket, - InfraSnapshotMetricsBucket, -} from './response_helpers'; - -describe('InfraOps ResponseHelpers', () => { - describe('isIPv4', () => { - it('should return true for IPv4', () => { - expect(isIPv4('192.168.2.4')).toBe(true); - }); - it('should return false for anything else', () => { - expect(isIPv4('0:0:0:0:0:0:0:1')).toBe(false); - }); - }); - - describe('getIPFromBucket', () => { - it('should return IPv4 address', () => { - const bucket: InfraSnapshotNodeGroupByBucket = { - key: { - id: 'example-01', - name: 'example-01', - }, - ip: { - hits: { - total: { value: 1 }, - hits: [ - { - _index: 'metricbeat-2019-01-01', - _type: '_doc', - _id: '29392939', - _score: null, - sort: [], - _source: { - host: { - ip: ['2001:db8:85a3::8a2e:370:7334', '192.168.1.4'], - }, - }, - }, - ], - }, - }, - }; - expect(getIPFromBucket('host', bucket)).toBe('192.168.1.4'); - }); - it('should NOT return ipv6 address', () => { - const bucket: InfraSnapshotNodeGroupByBucket = { - key: { - id: 'example-01', - name: 'example-01', - }, - ip: { - hits: { - total: { value: 1 }, - hits: [ - { - _index: 'metricbeat-2019-01-01', - _type: '_doc', - _id: '29392939', - _score: null, - sort: [], - _source: { - host: { - ip: ['2001:db8:85a3::8a2e:370:7334'], - }, - }, - }, - ], - }, - }, - }; - expect(getIPFromBucket('host', bucket)).toBe(null); - }); - }); - - describe('getMetricValueFromBucket', () => { - it('should return the value of a bucket with data', () => { - expect(getMetricValueFromBucket('custom', testBucket, 1)).toBe(0.5); - }); - it('should return the normalized value of a bucket with data', () => { - expect(getMetricValueFromBucket('cpu', testNormalizedBucket, 1)).toBe(50); - }); - it('should return null for a bucket with no data', () => { - expect(getMetricValueFromBucket('custom', testEmptyBucket, 1)).toBe(null); - }); - }); -}); - -// Hack to get around TypeScript -const buckets = [ - { - key: 'a', - doc_count: 1, - custom_1: { - value: 0.5, - }, - }, - { - key: 'b', - doc_count: 1, - cpu: { - value: 0.5, - normalized_value: 50, - }, - }, - { - key: 'c', - doc_count: 0, - }, -] as InfraSnapshotMetricsBucket[]; -const [testBucket, testNormalizedBucket, testEmptyBucket] = buckets; diff --git a/x-pack/plugins/infra/server/lib/snapshot/response_helpers.ts b/x-pack/plugins/infra/server/lib/snapshot/response_helpers.ts deleted file mode 100644 index 2652e362b7ef..000000000000 --- a/x-pack/plugins/infra/server/lib/snapshot/response_helpers.ts +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { isNumber, last, max, sum, get } from 'lodash'; -import moment from 'moment'; - -import { MetricsExplorerSeries } from '../../../common/http_api/metrics_explorer'; -import { getIntervalInSeconds } from '../../utils/get_interval_in_seconds'; -import { InfraSnapshotRequestOptions } from './types'; -import { findInventoryModel } from '../../../common/inventory_models'; -import { InventoryItemType, SnapshotMetricType } from '../../../common/inventory_models/types'; -import { SnapshotNodeMetric, SnapshotNodePath } from '../../../common/http_api/snapshot_api'; - -export interface InfraSnapshotNodeMetricsBucket { - key: { id: string }; - histogram: { - buckets: InfraSnapshotMetricsBucket[]; - }; -} - -// Jumping through TypeScript hoops here: -// We need an interface that has the known members 'key' and 'doc_count' and also -// an unknown number of members with unknown names but known format, containing the -// metrics. -// This union type is the only way I found to express this that TypeScript accepts. -export interface InfraSnapshotBucketWithKey { - key: string | number; - doc_count: number; -} - -export interface InfraSnapshotBucketWithValues { - [name: string]: { value: number; normalized_value?: number }; -} - -export type InfraSnapshotMetricsBucket = InfraSnapshotBucketWithKey & InfraSnapshotBucketWithValues; - -interface InfraSnapshotIpHit { - _index: string; - _type: string; - _id: string; - _score: number | null; - _source: { - host: { - ip: string[] | string; - }; - }; - sort: number[]; -} - -export interface InfraSnapshotNodeGroupByBucket { - key: { - id: string; - name: string; - [groupByField: string]: string; - }; - ip: { - hits: { - total: { value: number }; - hits: InfraSnapshotIpHit[]; - }; - }; -} - -export const isIPv4 = (subject: string) => /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/.test(subject); - -export const getIPFromBucket = ( - nodeType: InventoryItemType, - bucket: InfraSnapshotNodeGroupByBucket -): string | null => { - const inventoryModel = findInventoryModel(nodeType); - if (!inventoryModel.fields.ip) { - return null; - } - const ip = get(bucket, `ip.hits.hits[0]._source.${inventoryModel.fields.ip}`, null) as - | string[] - | null; - if (Array.isArray(ip)) { - return ip.find(isIPv4) || null; - } else if (typeof ip === 'string') { - return ip; - } - - return null; -}; - -export const getNodePath = ( - groupBucket: InfraSnapshotNodeGroupByBucket, - options: InfraSnapshotRequestOptions -): SnapshotNodePath[] => { - const node = groupBucket.key; - const path = options.groupBy.map((gb) => { - return { value: node[`${gb.field}`], label: node[`${gb.field}`] } as SnapshotNodePath; - }); - const ip = getIPFromBucket(options.nodeType, groupBucket); - path.push({ value: node.id, label: node.name || node.id, ip }); - return path; -}; - -interface NodeMetricsForLookup { - [nodeId: string]: InfraSnapshotMetricsBucket[]; -} - -export const getNodeMetricsForLookup = ( - metrics: InfraSnapshotNodeMetricsBucket[] -): NodeMetricsForLookup => { - return metrics.reduce((acc: NodeMetricsForLookup, metric) => { - acc[`${metric.key.id}`] = metric.histogram.buckets; - return acc; - }, {}); -}; - -// In the returned object, -// value contains the value from the last bucket spanning a full interval -// max and avg are calculated from all buckets returned for the timerange -export const getNodeMetrics = ( - nodeBuckets: InfraSnapshotMetricsBucket[], - options: InfraSnapshotRequestOptions -): SnapshotNodeMetric[] => { - if (!nodeBuckets) { - return options.metrics.map((metric) => ({ - name: metric.type, - value: null, - max: null, - avg: null, - })); - } - const lastBucket = findLastFullBucket(nodeBuckets, options); - if (!lastBucket) return []; - return options.metrics.map((metric, index) => { - const metricResult: SnapshotNodeMetric = { - name: metric.type, - value: getMetricValueFromBucket(metric.type, lastBucket, index), - max: calculateMax(nodeBuckets, metric.type, index), - avg: calculateAvg(nodeBuckets, metric.type, index), - }; - if (options.includeTimeseries) { - metricResult.timeseries = getTimeseriesData(nodeBuckets, metric.type, index); - } - return metricResult; - }); -}; - -const findLastFullBucket = ( - buckets: InfraSnapshotMetricsBucket[], - options: InfraSnapshotRequestOptions -) => { - const to = moment.utc(options.timerange.to); - const bucketSize = getIntervalInSeconds(options.timerange.interval); - return buckets.reduce((current, item) => { - const itemKey = isNumber(item.key) ? item.key : parseInt(item.key, 10); - const date = moment.utc(itemKey + bucketSize * 1000); - if (!date.isAfter(to) && item.doc_count > 0) { - return item; - } - return current; - }, last(buckets)); -}; - -export const getMetricValueFromBucket = ( - type: SnapshotMetricType, - bucket: InfraSnapshotMetricsBucket, - index: number -) => { - const key = type === 'custom' ? `custom_${index}` : type; - const metric = bucket[key]; - const value = metric && (metric.normalized_value || metric.value); - return isFinite(value) ? value : null; -}; - -function calculateMax( - buckets: InfraSnapshotMetricsBucket[], - type: SnapshotMetricType, - index: number -) { - return max(buckets.map((bucket) => getMetricValueFromBucket(type, bucket, index))) || 0; -} - -function calculateAvg( - buckets: InfraSnapshotMetricsBucket[], - type: SnapshotMetricType, - index: number -) { - return ( - sum(buckets.map((bucket) => getMetricValueFromBucket(type, bucket, index))) / buckets.length || - 0 - ); -} - -function getTimeseriesData( - buckets: InfraSnapshotMetricsBucket[], - type: SnapshotMetricType, - index: number -): MetricsExplorerSeries { - return { - id: type, - columns: [ - { name: 'timestamp', type: 'date' }, - { name: 'metric_0', type: 'number' }, - ], - rows: buckets.map((bucket) => ({ - timestamp: bucket.key as number, - metric_0: getMetricValueFromBucket(type, bucket, index), - })), - }; -} diff --git a/x-pack/plugins/infra/server/lib/snapshot/snapshot.ts b/x-pack/plugins/infra/server/lib/snapshot/snapshot.ts deleted file mode 100644 index 33d8e738a717..000000000000 --- a/x-pack/plugins/infra/server/lib/snapshot/snapshot.ts +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { InfraDatabaseSearchResponse, CallWithRequestParams } from '../adapters/framework'; - -import { JsonObject } from '../../../common/typed_json'; -import { SNAPSHOT_COMPOSITE_REQUEST_SIZE } from './constants'; -import { - getGroupedNodesSources, - getMetricsAggregations, - getMetricsSources, - getDateHistogramOffset, -} from './query_helpers'; -import { - getNodeMetrics, - getNodeMetricsForLookup, - getNodePath, - InfraSnapshotNodeGroupByBucket, - InfraSnapshotNodeMetricsBucket, -} from './response_helpers'; -import { getAllCompositeData } from '../../utils/get_all_composite_data'; -import { createAfterKeyHandler } from '../../utils/create_afterkey_handler'; -import { findInventoryModel } from '../../../common/inventory_models'; -import { InfraSnapshotRequestOptions } from './types'; -import { createTimeRangeWithInterval } from './create_timerange_with_interval'; -import { SnapshotNode } from '../../../common/http_api/snapshot_api'; - -type NamedSnapshotNode = SnapshotNode & { name: string }; - -export type ESSearchClient = ( - options: CallWithRequestParams -) => Promise>; -export class InfraSnapshot { - public async getNodes( - client: ESSearchClient, - options: InfraSnapshotRequestOptions - ): Promise<{ nodes: NamedSnapshotNode[]; interval: string }> { - // Both requestGroupedNodes and requestNodeMetrics may send several requests to elasticsearch - // in order to page through the results of their respective composite aggregations. - // Both chains of requests are supposed to run in parallel, and their results be merged - // when they have both been completed. - const timeRangeWithIntervalApplied = await createTimeRangeWithInterval(client, options); - const optionsWithTimerange = { ...options, timerange: timeRangeWithIntervalApplied }; - - const groupedNodesPromise = requestGroupedNodes(client, optionsWithTimerange); - const nodeMetricsPromise = requestNodeMetrics(client, optionsWithTimerange); - const [groupedNodeBuckets, nodeMetricBuckets] = await Promise.all([ - groupedNodesPromise, - nodeMetricsPromise, - ]); - return { - nodes: mergeNodeBuckets(groupedNodeBuckets, nodeMetricBuckets, options), - interval: timeRangeWithIntervalApplied.interval, - }; - } -} - -const bucketSelector = ( - response: InfraDatabaseSearchResponse<{}, InfraSnapshotAggregationResponse> -) => (response.aggregations && response.aggregations.nodes.buckets) || []; - -const handleAfterKey = createAfterKeyHandler( - 'body.aggregations.nodes.composite.after', - (input) => input?.aggregations?.nodes?.after_key -); - -const callClusterFactory = (search: ESSearchClient) => (opts: any) => - search<{}, InfraSnapshotAggregationResponse>(opts); - -const requestGroupedNodes = async ( - client: ESSearchClient, - options: InfraSnapshotRequestOptions -): Promise => { - const inventoryModel = findInventoryModel(options.nodeType); - const query = { - allowNoIndices: true, - index: `${options.sourceConfiguration.logAlias},${options.sourceConfiguration.metricAlias}`, - ignoreUnavailable: true, - body: { - query: { - bool: { - filter: buildFilters(options), - }, - }, - size: 0, - aggregations: { - nodes: { - composite: { - size: options.overrideCompositeSize || SNAPSHOT_COMPOSITE_REQUEST_SIZE, - sources: getGroupedNodesSources(options), - }, - aggs: { - ip: { - top_hits: { - sort: [{ [options.sourceConfiguration.fields.timestamp]: { order: 'desc' } }], - _source: { - includes: inventoryModel.fields.ip ? [inventoryModel.fields.ip] : [], - }, - size: 1, - }, - }, - }, - }, - }, - }, - }; - return getAllCompositeData( - callClusterFactory(client), - query, - bucketSelector, - handleAfterKey - ); -}; - -const calculateIndexPatterBasedOnMetrics = (options: InfraSnapshotRequestOptions) => { - const { metrics } = options; - if (metrics.every((m) => m.type === 'logRate')) { - return options.sourceConfiguration.logAlias; - } - if (metrics.some((m) => m.type === 'logRate')) { - return `${options.sourceConfiguration.logAlias},${options.sourceConfiguration.metricAlias}`; - } - return options.sourceConfiguration.metricAlias; -}; - -const requestNodeMetrics = async ( - client: ESSearchClient, - options: InfraSnapshotRequestOptions -): Promise => { - const index = calculateIndexPatterBasedOnMetrics(options); - const query = { - allowNoIndices: true, - index, - ignoreUnavailable: true, - body: { - query: { - bool: { - filter: buildFilters(options, false), - }, - }, - size: 0, - aggregations: { - nodes: { - composite: { - size: options.overrideCompositeSize || SNAPSHOT_COMPOSITE_REQUEST_SIZE, - sources: getMetricsSources(options), - }, - aggregations: { - histogram: { - date_histogram: { - field: options.sourceConfiguration.fields.timestamp, - interval: options.timerange.interval || '1m', - offset: getDateHistogramOffset(options.timerange.from, options.timerange.interval), - extended_bounds: { - min: options.timerange.from, - max: options.timerange.to, - }, - }, - aggregations: getMetricsAggregations(options), - }, - }, - }, - }, - }, - }; - return getAllCompositeData( - callClusterFactory(client), - query, - bucketSelector, - handleAfterKey - ); -}; - -// buckets can be InfraSnapshotNodeGroupByBucket[] or InfraSnapshotNodeMetricsBucket[] -// but typing this in a way that makes TypeScript happy is unreadable (if possible at all) -interface InfraSnapshotAggregationResponse { - nodes: { - buckets: any[]; - after_key: { [id: string]: string }; - }; -} - -const mergeNodeBuckets = ( - nodeGroupByBuckets: InfraSnapshotNodeGroupByBucket[], - nodeMetricsBuckets: InfraSnapshotNodeMetricsBucket[], - options: InfraSnapshotRequestOptions -): NamedSnapshotNode[] => { - const nodeMetricsForLookup = getNodeMetricsForLookup(nodeMetricsBuckets); - - return nodeGroupByBuckets.map((node) => { - return { - name: node.key.name || node.key.id, // For type safety; name can be derived from getNodePath but not in a TS-friendly way - path: getNodePath(node, options), - metrics: getNodeMetrics(nodeMetricsForLookup[node.key.id], options), - }; - }); -}; - -const createQueryFilterClauses = (filterQuery: JsonObject | undefined) => - filterQuery ? [filterQuery] : []; - -const buildFilters = (options: InfraSnapshotRequestOptions, withQuery = true) => { - let filters: any = [ - { - range: { - [options.sourceConfiguration.fields.timestamp]: { - gte: options.timerange.from, - lte: options.timerange.to, - format: 'epoch_millis', - }, - }, - }, - ]; - - if (withQuery) { - filters = [...createQueryFilterClauses(options.filterQuery), ...filters]; - } - - if (options.accountId) { - filters.push({ - term: { - 'cloud.account.id': options.accountId, - }, - }); - } - - if (options.region) { - filters.push({ - term: { - 'cloud.region': options.region, - }, - }); - } - - return filters; -}; diff --git a/x-pack/plugins/infra/server/lib/snapshot/types.ts b/x-pack/plugins/infra/server/lib/snapshot/types.ts deleted file mode 100644 index 7e17cb91c6a5..000000000000 --- a/x-pack/plugins/infra/server/lib/snapshot/types.ts +++ /dev/null @@ -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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { JsonObject } from '../../../common/typed_json'; -import { InfraSourceConfiguration } from '../../../common/graphql/types'; -import { SnapshotRequest } from '../../../common/http_api/snapshot_api'; - -export interface InfraSnapshotRequestOptions - extends Omit { - sourceConfiguration: InfraSourceConfiguration; - filterQuery: JsonObject | undefined; -} diff --git a/x-pack/plugins/infra/server/lib/sources/has_data.ts b/x-pack/plugins/infra/server/lib/sources/has_data.ts index 79b1375059dc..53297640e541 100644 --- a/x-pack/plugins/infra/server/lib/sources/has_data.ts +++ b/x-pack/plugins/infra/server/lib/sources/has_data.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESSearchClient } from '../snapshot'; +import { ESSearchClient } from '../metrics/types'; export const hasData = async (index: string, client: ESSearchClient) => { const params = { diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index 51f91d7189db..90b73b9a7585 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -19,7 +19,6 @@ import { InfraElasticsearchSourceStatusAdapter } from './lib/adapters/source_sta import { InfraFieldsDomain } from './lib/domains/fields_domain'; import { InfraLogEntriesDomain } from './lib/domains/log_entries_domain'; import { InfraMetricsDomain } from './lib/domains/metrics_domain'; -import { InfraSnapshot } from './lib/snapshot'; import { InfraSourceStatus } from './lib/source_status'; import { InfraSources } from './lib/sources'; import { InfraServerPluginDeps } from './lib/adapters/framework'; @@ -105,7 +104,6 @@ export class InfraServerPlugin { sources, } ); - const snapshot = new InfraSnapshot(); // register saved object types core.savedObjects.registerType(infraSourceConfigurationSavedObjectType); @@ -129,7 +127,6 @@ export class InfraServerPlugin { this.libs = { configuration: this.config, framework, - snapshot, sources, sourceStatus, ...domainLibs, diff --git a/x-pack/plugins/infra/server/routes/alerting/preview.ts b/x-pack/plugins/infra/server/routes/alerting/preview.ts index 5594323d706d..40d09dadfe05 100644 --- a/x-pack/plugins/infra/server/routes/alerting/preview.ts +++ b/x-pack/plugins/infra/server/routes/alerting/preview.ts @@ -82,7 +82,7 @@ export const initAlertPreviewRoute = ({ framework, sources }: InfraBackendLibs) callCluster, params: { criteria, filterQuery, nodeType }, lookback, - config: source.configuration, + source, alertInterval, }); diff --git a/x-pack/plugins/infra/server/routes/log_entries/entries.ts b/x-pack/plugins/infra/server/routes/log_entries/entries.ts index 2cd889d9c556..c1f63d9c2957 100644 --- a/x-pack/plugins/infra/server/routes/log_entries/entries.ts +++ b/x-pack/plugins/infra/server/routes/log_entries/entries.ts @@ -4,14 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Boom from 'boom'; - -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { schema } from '@kbn/config-schema'; - -import { throwErrors } from '../../../common/runtime_types'; +import { createValidationFunction } from '../../../common/runtime_types'; import { InfraBackendLibs } from '../../lib/infra_types'; import { @@ -22,22 +15,16 @@ import { import { parseFilterQuery } from '../../utils/serialized_query'; import { LogEntriesParams } from '../../lib/domains/log_entries_domain'; -const escapeHatch = schema.object({}, { unknowns: 'allow' }); - export const initLogEntriesRoute = ({ framework, logEntries }: InfraBackendLibs) => { framework.registerRoute( { method: 'post', path: LOG_ENTRIES_PATH, - validate: { body: escapeHatch }, + validate: { body: createValidationFunction(logEntriesRequestRT) }, }, async (requestContext, request, response) => { try { - const payload = pipe( - logEntriesRequestRT.decode(request.body), - fold(throwErrors(Boom.badRequest), identity) - ); - + const payload = request.body; const { startTimestamp: startTimestamp, endTimestamp: endTimestamp, diff --git a/x-pack/plugins/infra/server/routes/log_entries/item.ts b/x-pack/plugins/infra/server/routes/log_entries/item.ts index 85dba8f598a8..67ca481ff4fc 100644 --- a/x-pack/plugins/infra/server/routes/log_entries/item.ts +++ b/x-pack/plugins/infra/server/routes/log_entries/item.ts @@ -4,14 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import Boom from 'boom'; - -import { pipe } from 'fp-ts/lib/pipeable'; -import { fold } from 'fp-ts/lib/Either'; -import { identity } from 'fp-ts/lib/function'; -import { schema } from '@kbn/config-schema'; - -import { throwErrors } from '../../../common/runtime_types'; +import { createValidationFunction } from '../../../common/runtime_types'; import { InfraBackendLibs } from '../../lib/infra_types'; import { @@ -20,22 +13,16 @@ import { logEntriesItemResponseRT, } from '../../../common/http_api'; -const escapeHatch = schema.object({}, { unknowns: 'allow' }); - export const initLogEntriesItemRoute = ({ framework, sources, logEntries }: InfraBackendLibs) => { framework.registerRoute( { method: 'post', path: LOG_ENTRIES_ITEM_PATH, - validate: { body: escapeHatch }, + validate: { body: createValidationFunction(logEntriesItemRequestRT) }, }, async (requestContext, request, response) => { try { - const payload = pipe( - logEntriesItemRequestRT.decode(request.body), - fold(throwErrors(Boom.badRequest), identity) - ); - + const payload = request.body; const { id, sourceId } = payload; const sourceConfiguration = ( await sources.getSourceConfiguration(requestContext.core.savedObjects.client, sourceId) diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/find_interval_for_metrics.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/find_interval_for_metrics.ts index 876bbb419944..8ab0f4a44c85 100644 --- a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/find_interval_for_metrics.ts +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/find_interval_for_metrics.ts @@ -7,9 +7,9 @@ import { uniq } from 'lodash'; import LRU from 'lru-cache'; import { MetricsExplorerRequestBody } from '../../../../common/http_api'; -import { ESSearchClient } from '../../../lib/snapshot'; import { getDatasetForField } from './get_dataset_for_field'; import { calculateMetricInterval } from '../../../utils/calculate_metric_interval'; +import { ESSearchClient } from '../../../lib/metrics/types'; const cache = new LRU({ max: 100, diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts index 94e91d32b14b..85bb5b106c87 100644 --- a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESSearchClient } from '../../../lib/snapshot'; +import { ESSearchClient } from '../../../lib/metrics/types'; interface EventDatasetHit { _source: { diff --git a/x-pack/plugins/infra/server/routes/snapshot/index.ts b/x-pack/plugins/infra/server/routes/snapshot/index.ts index 00bc1e74ea87..3f09ae89bc97 100644 --- a/x-pack/plugins/infra/server/routes/snapshot/index.ts +++ b/x-pack/plugins/infra/server/routes/snapshot/index.ts @@ -10,10 +10,10 @@ import { fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import { InfraBackendLibs } from '../../lib/infra_types'; import { UsageCollector } from '../../usage/usage_collector'; -import { parseFilterQuery } from '../../utils/serialized_query'; import { SnapshotRequestRT, SnapshotNodeResponseRT } from '../../../common/http_api/snapshot_api'; import { throwErrors } from '../../../common/runtime_types'; import { createSearchClient } from '../../lib/create_search_client'; +import { getNodes } from './lib/get_nodes'; const escapeHatch = schema.object({}, { unknowns: 'allow' }); @@ -30,43 +30,22 @@ export const initSnapshotRoute = (libs: InfraBackendLibs) => { }, async (requestContext, request, response) => { try { - const { - filterQuery, - nodeType, - groupBy, - sourceId, - metrics, - timerange, - accountId, - region, - includeTimeseries, - overrideCompositeSize, - } = pipe( + const snapshotRequest = pipe( SnapshotRequestRT.decode(request.body), fold(throwErrors(Boom.badRequest), identity) ); + const source = await libs.sources.getSourceConfiguration( requestContext.core.savedObjects.client, - sourceId + snapshotRequest.sourceId ); - UsageCollector.countNode(nodeType); - const options = { - filterQuery: parseFilterQuery(filterQuery), - accountId, - region, - nodeType, - groupBy, - sourceConfiguration: source.configuration, - metrics, - timerange, - includeTimeseries, - overrideCompositeSize, - }; + UsageCollector.countNode(snapshotRequest.nodeType); const client = createSearchClient(requestContext, framework); - const nodesWithInterval = await libs.snapshot.getNodes(client, options); + const snapshotResponse = await getNodes(client, snapshotRequest, source); + return response.ok({ - body: SnapshotNodeResponseRT.encode(nodesWithInterval), + body: SnapshotNodeResponseRT.encode(snapshotResponse), }); } catch (error) { return response.internalError({ diff --git a/x-pack/plugins/infra/server/routes/snapshot/lib/apply_metadata_to_last_path.ts b/x-pack/plugins/infra/server/routes/snapshot/lib/apply_metadata_to_last_path.ts new file mode 100644 index 000000000000..f41d76bbc156 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/snapshot/lib/apply_metadata_to_last_path.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { get, last, first, isArray } from 'lodash'; +import { findInventoryFields } from '../../../../common/inventory_models'; +import { + SnapshotRequest, + SnapshotNodePath, + SnapshotNode, + MetricsAPISeries, + MetricsAPIRow, +} from '../../../../common/http_api'; +import { META_KEY } from './constants'; +import { InfraSource } from '../../../lib/sources'; + +export const isIPv4 = (subject: string) => /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/.test(subject); + +type RowWithMetadata = MetricsAPIRow & { + [META_KEY]: object[]; +}; + +export const applyMetadataToLastPath = ( + series: MetricsAPISeries, + node: SnapshotNode, + snapshotRequest: SnapshotRequest, + source: InfraSource +): SnapshotNodePath[] => { + // First we need to find a row with metadata + const rowWithMeta = series.rows.find( + (row) => (row[META_KEY] && isArray(row[META_KEY]) && (row[META_KEY] as object[]).length) || 0 + ) as RowWithMetadata | undefined; + + if (rowWithMeta) { + // We need just the first doc, there should only be one + const firstMetaDoc = first(rowWithMeta[META_KEY]); + // We also need the last path to add the metadata to + const lastPath = last(node.path); + if (firstMetaDoc && lastPath) { + // We will need the inventory fields so we can use the field paths to get + // the values from the metadata document + const inventoryFields = findInventoryFields( + snapshotRequest.nodeType, + source.configuration.fields + ); + // Set the label as the name and fallback to the id OR path.value + lastPath.label = get(firstMetaDoc, inventoryFields.name, lastPath.value); + // If the inventory fields contain an ip address, we need to try and set that + // on the path object. IP addersses are typically stored as multiple fields. We will + // use the first IPV4 address we find. + if (inventoryFields.ip) { + const ipAddresses = get(firstMetaDoc, inventoryFields.ip) as string[]; + if (Array.isArray(ipAddresses)) { + lastPath.ip = ipAddresses.find(isIPv4) || null; + } else if (typeof ipAddresses === 'string') { + lastPath.ip = ipAddresses; + } + } + return [...node.path.slice(0, node.path.length - 1), lastPath]; + } + } + return node.path; +}; diff --git a/x-pack/plugins/infra/server/routes/snapshot/lib/calculate_index_pattern_based_on_metrics.ts b/x-pack/plugins/infra/server/routes/snapshot/lib/calculate_index_pattern_based_on_metrics.ts new file mode 100644 index 000000000000..4218aecfe74a --- /dev/null +++ b/x-pack/plugins/infra/server/routes/snapshot/lib/calculate_index_pattern_based_on_metrics.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SnapshotRequest } from '../../../../common/http_api'; +import { InfraSource } from '../../../lib/sources'; + +export const calculateIndexPatterBasedOnMetrics = ( + options: SnapshotRequest, + source: InfraSource +) => { + const { metrics } = options; + if (metrics.every((m) => m.type === 'logRate')) { + return source.configuration.logAlias; + } + if (metrics.some((m) => m.type === 'logRate')) { + return `${source.configuration.logAlias},${source.configuration.metricAlias}`; + } + return source.configuration.metricAlias; +}; diff --git a/x-pack/plugins/infra/server/lib/snapshot/index.ts b/x-pack/plugins/infra/server/routes/snapshot/lib/constants.ts similarity index 85% rename from x-pack/plugins/infra/server/lib/snapshot/index.ts rename to x-pack/plugins/infra/server/routes/snapshot/lib/constants.ts index 8db54da80364..563c72022443 100644 --- a/x-pack/plugins/infra/server/lib/snapshot/index.ts +++ b/x-pack/plugins/infra/server/routes/snapshot/lib/constants.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export * from './snapshot'; +export const META_KEY = '__metadata__'; diff --git a/x-pack/plugins/infra/server/routes/snapshot/lib/copy_missing_metrics.ts b/x-pack/plugins/infra/server/routes/snapshot/lib/copy_missing_metrics.ts new file mode 100644 index 000000000000..36397862e415 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/snapshot/lib/copy_missing_metrics.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { memoize, last, first } from 'lodash'; +import { SnapshotNode, SnapshotNodeResponse } from '../../../../common/http_api'; + +const createMissingMetricFinder = (nodes: SnapshotNode[]) => + memoize((id: string) => { + const nodeWithMetrics = nodes.find((node) => { + const lastPath = last(node.path); + const metric = first(node.metrics); + return lastPath && metric && lastPath.value === id && metric.value !== null; + }); + if (nodeWithMetrics) { + return nodeWithMetrics.metrics; + } + }); + +/** + * This function will look for nodes with missing data and try to find a node to copy the data from. + * This functionality exists to suppor the use case where the user requests a group by on "Service type". + * Since that grouping naturally excludeds every metric (except the metric for the service.type), we still + * want to display the node with a value. A good example is viewing hosts by CPU Usage and grouping by service + * Without this every service but `system` would be null. + */ +export const copyMissingMetrics = (response: SnapshotNodeResponse) => { + const { nodes } = response; + const find = createMissingMetricFinder(nodes); + const newNodes = nodes.map((node) => { + const lastPath = last(node.path); + const metric = first(node.metrics); + const allRowsNull = metric?.timeseries?.rows.every((r) => r.metric_0 == null) ?? true; + if (lastPath && metric && metric.value === null && allRowsNull) { + const newMetrics = find(lastPath.value); + if (newMetrics) { + return { ...node, metrics: newMetrics }; + } + } + return node; + }); + return { ...response, nodes: newNodes }; +}; diff --git a/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts b/x-pack/plugins/infra/server/routes/snapshot/lib/create_timerange_with_interval.ts similarity index 80% rename from x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts rename to x-pack/plugins/infra/server/routes/snapshot/lib/create_timerange_with_interval.ts index 719ffdb8fa7c..827e0901c1c0 100644 --- a/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts +++ b/x-pack/plugins/infra/server/routes/snapshot/lib/create_timerange_with_interval.ts @@ -5,14 +5,16 @@ */ import { uniq } from 'lodash'; -import { InfraSnapshotRequestOptions } from './types'; -import { getMetricsAggregations } from './query_helpers'; -import { calculateMetricInterval } from '../../utils/calculate_metric_interval'; -import { MetricsUIAggregation, ESBasicMetricAggRT } from '../../../common/inventory_models/types'; -import { getDatasetForField } from '../../routes/metrics_explorer/lib/get_dataset_for_field'; -import { InfraTimerangeInput } from '../../../common/http_api/snapshot_api'; -import { ESSearchClient } from '.'; -import { getIntervalInSeconds } from '../../utils/get_interval_in_seconds'; +import { InfraTimerangeInput } from '../../../../common/http_api'; +import { ESSearchClient } from '../../../lib/metrics/types'; +import { getIntervalInSeconds } from '../../../utils/get_interval_in_seconds'; +import { calculateMetricInterval } from '../../../utils/calculate_metric_interval'; +import { getMetricsAggregations, InfraSnapshotRequestOptions } from './get_metrics_aggregations'; +import { + MetricsUIAggregation, + ESBasicMetricAggRT, +} from '../../../../common/inventory_models/types'; +import { getDatasetForField } from '../../metrics_explorer/lib/get_dataset_for_field'; const createInterval = async (client: ESSearchClient, options: InfraSnapshotRequestOptions) => { const { timerange } = options; diff --git a/x-pack/plugins/infra/server/routes/snapshot/lib/get_metrics_aggregations.ts b/x-pack/plugins/infra/server/routes/snapshot/lib/get_metrics_aggregations.ts new file mode 100644 index 000000000000..2421469eb1bd --- /dev/null +++ b/x-pack/plugins/infra/server/routes/snapshot/lib/get_metrics_aggregations.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { JsonObject } from '../../../../common/typed_json'; +import { + InventoryItemType, + MetricsUIAggregation, + MetricsUIAggregationRT, +} from '../../../../common/inventory_models/types'; +import { + SnapshotMetricInput, + SnapshotCustomMetricInputRT, + SnapshotRequest, +} from '../../../../common/http_api'; +import { findInventoryModel } from '../../../../common/inventory_models'; +import { networkTraffic } from '../../../../common/inventory_models/shared/metrics/snapshot/network_traffic'; +import { InfraSourceConfiguration } from '../../../lib/sources'; + +export interface InfraSnapshotRequestOptions + extends Omit { + sourceConfiguration: InfraSourceConfiguration; + filterQuery: JsonObject | undefined; +} + +export const metricToAggregation = ( + nodeType: InventoryItemType, + metric: SnapshotMetricInput, + index: number +) => { + const inventoryModel = findInventoryModel(nodeType); + if (SnapshotCustomMetricInputRT.is(metric)) { + if (metric.aggregation === 'rate') { + return networkTraffic(`custom_${index}`, metric.field); + } + return { + [`custom_${index}`]: { + [metric.aggregation]: { + field: metric.field, + }, + }, + }; + } + return inventoryModel.metrics.snapshot?.[metric.type]; +}; + +export const getMetricsAggregations = ( + options: InfraSnapshotRequestOptions +): MetricsUIAggregation => { + const { metrics } = options; + return metrics.reduce((aggs, metric, index) => { + const aggregation = metricToAggregation(options.nodeType, metric, index); + if (!MetricsUIAggregationRT.is(aggregation)) { + throw new Error( + i18n.translate('xpack.infra.snapshot.missingSnapshotMetricError', { + defaultMessage: 'The aggregation for {metric} for {nodeType} is not available.', + values: { + nodeType: options.nodeType, + metric: metric.type, + }, + }) + ); + } + return { ...aggs, ...aggregation }; + }, {}); +}; diff --git a/x-pack/plugins/infra/server/routes/snapshot/lib/get_nodes.ts b/x-pack/plugins/infra/server/routes/snapshot/lib/get_nodes.ts new file mode 100644 index 000000000000..9332d5aee1f5 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/snapshot/lib/get_nodes.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SnapshotRequest } from '../../../../common/http_api'; +import { ESSearchClient } from '../../../lib/metrics/types'; +import { InfraSource } from '../../../lib/sources'; +import { transformRequestToMetricsAPIRequest } from './transform_request_to_metrics_api_request'; +import { queryAllData } from './query_all_data'; +import { transformMetricsApiResponseToSnapshotResponse } from './trasform_metrics_ui_response'; +import { copyMissingMetrics } from './copy_missing_metrics'; + +export const getNodes = async ( + client: ESSearchClient, + snapshotRequest: SnapshotRequest, + source: InfraSource +) => { + const metricsApiRequest = await transformRequestToMetricsAPIRequest( + client, + source, + snapshotRequest + ); + const metricsApiResponse = await queryAllData(client, metricsApiRequest); + return copyMissingMetrics( + transformMetricsApiResponseToSnapshotResponse( + metricsApiRequest, + snapshotRequest, + source, + metricsApiResponse + ) + ); +}; diff --git a/x-pack/plugins/infra/server/routes/snapshot/lib/query_all_data.ts b/x-pack/plugins/infra/server/routes/snapshot/lib/query_all_data.ts new file mode 100644 index 000000000000..a9d2352cf55b --- /dev/null +++ b/x-pack/plugins/infra/server/routes/snapshot/lib/query_all_data.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { MetricsAPIRequest, MetricsAPIResponse } from '../../../../common/http_api'; +import { ESSearchClient } from '../../../lib/metrics/types'; +import { query } from '../../../lib/metrics'; + +const handleResponse = ( + client: ESSearchClient, + options: MetricsAPIRequest, + previousResponse?: MetricsAPIResponse +) => async (resp: MetricsAPIResponse): Promise => { + const combinedResponse = previousResponse + ? { + ...previousResponse, + series: [...previousResponse.series, ...resp.series], + info: resp.info, + } + : resp; + if (resp.info.afterKey) { + return query(client, { ...options, afterKey: resp.info.afterKey }).then( + handleResponse(client, options, combinedResponse) + ); + } + return combinedResponse; +}; + +export const queryAllData = (client: ESSearchClient, options: MetricsAPIRequest) => { + return query(client, options).then(handleResponse(client, options)); +}; diff --git a/x-pack/plugins/infra/server/routes/snapshot/lib/transform_request_to_metrics_api_request.ts b/x-pack/plugins/infra/server/routes/snapshot/lib/transform_request_to_metrics_api_request.ts new file mode 100644 index 000000000000..700f4ef39bb6 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/snapshot/lib/transform_request_to_metrics_api_request.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { findInventoryFields } from '../../../../common/inventory_models'; +import { MetricsAPIRequest, SnapshotRequest } from '../../../../common/http_api'; +import { ESSearchClient } from '../../../lib/metrics/types'; +import { InfraSource } from '../../../lib/sources'; +import { createTimeRangeWithInterval } from './create_timerange_with_interval'; +import { parseFilterQuery } from '../../../utils/serialized_query'; +import { transformSnapshotMetricsToMetricsAPIMetrics } from './transform_snapshot_metrics_to_metrics_api_metrics'; +import { calculateIndexPatterBasedOnMetrics } from './calculate_index_pattern_based_on_metrics'; +import { META_KEY } from './constants'; + +export const transformRequestToMetricsAPIRequest = async ( + client: ESSearchClient, + source: InfraSource, + snapshotRequest: SnapshotRequest +): Promise => { + const timeRangeWithIntervalApplied = await createTimeRangeWithInterval(client, { + ...snapshotRequest, + filterQuery: parseFilterQuery(snapshotRequest.filterQuery), + sourceConfiguration: source.configuration, + }); + + const metricsApiRequest: MetricsAPIRequest = { + indexPattern: calculateIndexPatterBasedOnMetrics(snapshotRequest, source), + timerange: { + field: source.configuration.fields.timestamp, + from: timeRangeWithIntervalApplied.from, + to: timeRangeWithIntervalApplied.to, + interval: timeRangeWithIntervalApplied.interval, + }, + metrics: transformSnapshotMetricsToMetricsAPIMetrics(snapshotRequest), + limit: snapshotRequest.overrideCompositeSize ? snapshotRequest.overrideCompositeSize : 10, + alignDataToEnd: true, + }; + + const filters = []; + const parsedFilters = parseFilterQuery(snapshotRequest.filterQuery); + if (parsedFilters) { + filters.push(parsedFilters); + } + + if (snapshotRequest.accountId) { + filters.push({ term: { 'cloud.account.id': snapshotRequest.accountId } }); + } + + if (snapshotRequest.region) { + filters.push({ term: { 'cloud.region': snapshotRequest.region } }); + } + + const inventoryFields = findInventoryFields( + snapshotRequest.nodeType, + source.configuration.fields + ); + const groupBy = snapshotRequest.groupBy.map((g) => g.field).filter(Boolean) as string[]; + metricsApiRequest.groupBy = [...groupBy, inventoryFields.id]; + + const metaAggregation = { + id: META_KEY, + aggregations: { + [META_KEY]: { + top_hits: { + size: 1, + _source: [inventoryFields.name], + sort: [{ [source.configuration.fields.timestamp]: 'desc' }], + }, + }, + }, + }; + if (inventoryFields.ip) { + metaAggregation.aggregations[META_KEY].top_hits._source.push(inventoryFields.ip); + } + metricsApiRequest.metrics.push(metaAggregation); + + if (filters.length) { + metricsApiRequest.filters = filters; + } + + return metricsApiRequest; +}; diff --git a/x-pack/plugins/infra/server/routes/snapshot/lib/transform_snapshot_metrics_to_metrics_api_metrics.ts b/x-pack/plugins/infra/server/routes/snapshot/lib/transform_snapshot_metrics_to_metrics_api_metrics.ts new file mode 100644 index 000000000000..6f7c88eda5d7 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/snapshot/lib/transform_snapshot_metrics_to_metrics_api_metrics.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { networkTraffic } from '../../../../common/inventory_models/shared/metrics/snapshot/network_traffic'; +import { findInventoryModel } from '../../../../common/inventory_models'; +import { + MetricsAPIMetric, + SnapshotRequest, + SnapshotCustomMetricInputRT, +} from '../../../../common/http_api'; + +export const transformSnapshotMetricsToMetricsAPIMetrics = ( + snapshotRequest: SnapshotRequest +): MetricsAPIMetric[] => { + return snapshotRequest.metrics.map((metric, index) => { + const inventoryModel = findInventoryModel(snapshotRequest.nodeType); + if (SnapshotCustomMetricInputRT.is(metric)) { + const customId = `custom_${index}`; + if (metric.aggregation === 'rate') { + return { id: customId, aggregations: networkTraffic(customId, metric.field) }; + } + return { + id: customId, + aggregations: { + [customId]: { + [metric.aggregation]: { + field: metric.field, + }, + }, + }, + }; + } + return { id: metric.type, aggregations: inventoryModel.metrics.snapshot?.[metric.type] }; + }); +}; diff --git a/x-pack/plugins/infra/server/routes/snapshot/lib/trasform_metrics_ui_response.ts b/x-pack/plugins/infra/server/routes/snapshot/lib/trasform_metrics_ui_response.ts new file mode 100644 index 000000000000..309598d71c36 --- /dev/null +++ b/x-pack/plugins/infra/server/routes/snapshot/lib/trasform_metrics_ui_response.ts @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { get, max, sum, last, isNumber } from 'lodash'; +import { SnapshotMetricType } from '../../../../common/inventory_models/types'; +import { + MetricsAPIResponse, + SnapshotNodeResponse, + MetricsAPIRequest, + MetricsExplorerColumnType, + MetricsAPIRow, + SnapshotRequest, + SnapshotNodePath, + SnapshotNodeMetric, +} from '../../../../common/http_api'; +import { META_KEY } from './constants'; +import { InfraSource } from '../../../lib/sources'; +import { applyMetadataToLastPath } from './apply_metadata_to_last_path'; + +const getMetricValue = (row: MetricsAPIRow) => { + if (!isNumber(row.metric_0)) return null; + const value = row.metric_0; + return isFinite(value) ? value : null; +}; + +const calculateMax = (rows: MetricsAPIRow[]) => { + return max(rows.map(getMetricValue)) || 0; +}; + +const calculateAvg = (rows: MetricsAPIRow[]): number => { + return sum(rows.map(getMetricValue)) / rows.length || 0; +}; + +const getLastValue = (rows: MetricsAPIRow[]) => { + const row = last(rows); + if (!row) return null; + return getMetricValue(row); +}; + +export const transformMetricsApiResponseToSnapshotResponse = ( + options: MetricsAPIRequest, + snapshotRequest: SnapshotRequest, + source: InfraSource, + metricsApiResponse: MetricsAPIResponse +): SnapshotNodeResponse => { + const nodes = metricsApiResponse.series.map((series) => { + const node = { + metrics: options.metrics + .filter((m) => m.id !== META_KEY) + .map((metric) => { + const name = metric.id as SnapshotMetricType; + const timeseries = { + id: name, + columns: [ + { name: 'timestamp', type: 'date' as MetricsExplorerColumnType }, + { name: 'metric_0', type: 'number' as MetricsExplorerColumnType }, + ], + rows: series.rows.map((row) => { + return { timestamp: row.timestamp, metric_0: get(row, metric.id, null) }; + }), + }; + const maxValue = calculateMax(timeseries.rows); + const avg = calculateAvg(timeseries.rows); + const value = getLastValue(timeseries.rows); + const nodeMetric: SnapshotNodeMetric = { name, max: maxValue, value, avg }; + if (snapshotRequest.includeTimeseries) { + nodeMetric.timeseries = timeseries; + } + return nodeMetric; + }), + path: + series.keys?.map((key) => { + return { value: key, label: key } as SnapshotNodePath; + }) ?? [], + name: '', + }; + + const path = applyMetadataToLastPath(series, node, snapshotRequest, source); + const lastPath = last(path); + const name = (lastPath && lastPath.label) || 'N/A'; + return { ...node, path, name }; + }); + return { nodes, interval: `${metricsApiResponse.info.interval}s` }; +}; diff --git a/x-pack/plugins/infra/server/utils/calculate_metric_interval.ts b/x-pack/plugins/infra/server/utils/calculate_metric_interval.ts index a3d674b324ae..6d16e045d26d 100644 --- a/x-pack/plugins/infra/server/utils/calculate_metric_interval.ts +++ b/x-pack/plugins/infra/server/utils/calculate_metric_interval.ts @@ -8,7 +8,7 @@ import { findInventoryModel } from '../../common/inventory_models'; // import { KibanaFramework } from '../lib/adapters/framework/kibana_framework_adapter'; import { InventoryItemType } from '../../common/inventory_models/types'; -import { ESSearchClient } from '../lib/snapshot'; +import { ESSearchClient } from '../lib/metrics/types'; interface Options { indexPattern: string; diff --git a/x-pack/plugins/ingest_manager/common/openapi/spec_oas3.json b/x-pack/plugins/ingest_manager/common/openapi/spec_oas3.json index d75a914e080d..b7856e6d5740 100644 --- a/x-pack/plugins/ingest_manager/common/openapi/spec_oas3.json +++ b/x-pack/plugins/ingest_manager/common/openapi/spec_oas3.json @@ -1425,11 +1425,13 @@ }, "icons": [ { - "src": "/package/coredns-1.0.1/img/icon.png", + "path": "/package/coredns-1.0.1/img/icon.png", + "src": "/img/icon.png", "size": "1800x1800" }, { - "src": "/package/coredns-1.0.1/img/icon.svg", + "path": "/package/coredns-1.0.1/img/icon.svg", + "src": "/img/icon.svg", "size": "255x144", "type": "image/svg+xml" } @@ -1704,7 +1706,8 @@ }, "icons": [ { - "src": "/package/endpoint/0.3.0/img/logo-endpoint-64-color.svg", + "path": "/package/endpoint/0.3.0/img/logo-endpoint-64-color.svg", + "src": "/img/logo-endpoint-64-color.svg", "size": "16x16", "type": "image/svg+xml" } @@ -2001,7 +2004,8 @@ "download": "/epr/aws/aws-0.0.3.tar.gz", "icons": [ { - "src": "/package/aws/0.0.3/img/logo_aws.svg", + "path": "/package/aws/0.0.3/img/logo_aws.svg", + "src": "/img/logo_aws.svg", "title": "logo aws", "size": "32x32", "type": "image/svg+xml" @@ -2019,7 +2023,8 @@ "download": "/epr/endpoint/endpoint-0.1.0.tar.gz", "icons": [ { - "src": "/package/endpoint/0.1.0/img/logo-endpoint-64-color.svg", + "path": "/package/endpoint/0.1.0/img/logo-endpoint-64-color.svg", + "src": "/img/logo-endpoint-64-color.svg", "size": "16x16", "type": "image/svg+xml" } @@ -2087,7 +2092,8 @@ "download": "/epr/log/log-0.9.0.tar.gz", "icons": [ { - "src": "/package/log/0.9.0/img/icon.svg", + "path": "/package/log/0.9.0/img/icon.svg", + "src": "/img/icon.svg", "type": "image/svg+xml" } ], @@ -2103,7 +2109,8 @@ "download": "/epr/longdocs/longdocs-1.0.4.tar.gz", "icons": [ { - "src": "/package/longdocs/1.0.4/img/icon.svg", + "path": "/package/longdocs/1.0.4/img/icon.svg", + "src": "/img/icon.svg", "type": "image/svg+xml" } ], @@ -2119,7 +2126,8 @@ "download": "/epr/metricsonly/metricsonly-2.0.1.tar.gz", "icons": [ { - "src": "/package/metricsonly/2.0.1/img/icon.svg", + "path": "/package/metricsonly/2.0.1/img/icon.svg", + "src": "/img/icon.svg", "type": "image/svg+xml" } ], @@ -2135,7 +2143,8 @@ "download": "/epr/multiversion/multiversion-1.1.0.tar.gz", "icons": [ { - "src": "/package/multiversion/1.1.0/img/icon.svg", + "path": "/package/multiversion/1.1.0/img/icon.svg", + "src": "/img/icon.svg", "type": "image/svg+xml" } ], @@ -2151,7 +2160,8 @@ "download": "/epr/mysql/mysql-0.1.0.tar.gz", "icons": [ { - "src": "/package/mysql/0.1.0/img/logo_mysql.svg", + "path": "/package/mysql/0.1.0/img/logo_mysql.svg", + "src": "/img/logo_mysql.svg", "title": "logo mysql", "size": "32x32", "type": "image/svg+xml" @@ -2169,7 +2179,8 @@ "download": "/epr/nginx/nginx-0.1.0.tar.gz", "icons": [ { - "src": "/package/nginx/0.1.0/img/logo_nginx.svg", + "path": "/package/nginx/0.1.0/img/logo_nginx.svg", + "src": "/img/logo_nginx.svg", "title": "logo nginx", "size": "32x32", "type": "image/svg+xml" @@ -2187,7 +2198,8 @@ "download": "/epr/redis/redis-0.1.0.tar.gz", "icons": [ { - "src": "/package/redis/0.1.0/img/logo_redis.svg", + "path": "/package/redis/0.1.0/img/logo_redis.svg", + "src": "/img/logo_redis.svg", "title": "logo redis", "size": "32x32", "type": "image/svg+xml" @@ -2205,7 +2217,8 @@ "download": "/epr/reference/reference-1.0.0.tar.gz", "icons": [ { - "src": "/package/reference/1.0.0/img/icon.svg", + "path": "/package/reference/1.0.0/img/icon.svg", + "src": "/img/icon.svg", "size": "32x32", "type": "image/svg+xml" } @@ -2222,7 +2235,8 @@ "download": "/epr/system/system-0.1.0.tar.gz", "icons": [ { - "src": "/package/system/0.1.0/img/system.svg", + "path": "/package/system/0.1.0/img/system.svg", + "src": "/img/system.svg", "title": "system", "size": "1000x1000", "type": "image/svg+xml" @@ -3913,11 +3927,20 @@ "src": { "type": "string" }, + "path": { + "type": "string" + }, "title": { "type": "string" + }, + "size": { + "type": "string" + }, + "type": { + "type": "string" } }, - "required": ["src"] + "required": ["src", "path"] } }, "icons": { diff --git a/x-pack/plugins/ingest_manager/common/types/models/epm.ts b/x-pack/plugins/ingest_manager/common/types/models/epm.ts index 140a76ac85e6..8bc5d9f7210b 100644 --- a/x-pack/plugins/ingest_manager/common/types/models/epm.ts +++ b/x-pack/plugins/ingest_manager/common/types/models/epm.ts @@ -19,6 +19,8 @@ export enum InstallStatus { uninstalling = 'uninstalling', } +export type InstallType = 'reinstall' | 'reupdate' | 'rollback' | 'update' | 'install'; + export type EpmPackageInstallStatus = 'installed' | 'installing'; export type DetailViewPanelName = 'overview' | 'usages' | 'settings'; @@ -38,6 +40,7 @@ export enum ElasticsearchAssetType { ingestPipeline = 'ingest_pipeline', indexTemplate = 'index_template', ilmPolicy = 'ilm_policy', + transform = 'transform', } export enum AgentAssetType { @@ -71,10 +74,8 @@ export interface RegistryPackage { } interface RegistryImage { - // https://github.com/elastic/package-registry/blob/master/util/package.go#L74 - // says src is potentially missing but I couldn't find any examples - // it seems like src should be required. How can you have an image with no reference to the content? src: string; + path: string; title?: string; size?: string; type?: string; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_package_icon_type.ts b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_package_icon_type.ts index e5a7191372e9..690ffdf46f70 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_package_icon_type.ts +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/hooks/use_package_icon_type.ts @@ -42,7 +42,7 @@ export const usePackageIconType = ({ const svgIcons = (paramIcons || iconList)?.filter( (iconDef) => iconDef.type === 'image/svg+xml' ); - const localIconSrc = Array.isArray(svgIcons) && svgIcons[0]?.src; + const localIconSrc = Array.isArray(svgIcons) && (svgIcons[0].path || svgIcons[0].src); if (localIconSrc) { CACHED_ICONS.set(pkgKey, toImage(localIconSrc)); setIconType(CACHED_ICONS.get(pkgKey) || ''); diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_select_agent_policy.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_select_agent_policy.tsx index 9f48be54f866..ccf9e45ebc4f 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_select_agent_policy.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/create_package_policy_page/step_select_agent_policy.tsx @@ -83,7 +83,7 @@ export const StepSelectAgentPolicy: React.FunctionComponent<{ data: agentPoliciesData, error: agentPoliciesError, isLoading: isAgentPoliciesLoading, - sendRequest: refreshAgentPolicies, + resendRequest: refreshAgentPolicies, } = useGetAgentPolicies({ page: 1, perPage: 1000, diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/hooks/use_agent_status.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/hooks/use_agent_status.tsx index 71dcd728d5d1..3483d8dee045 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/hooks/use_agent_status.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/details_page/hooks/use_agent_status.tsx @@ -25,7 +25,7 @@ export function useGetAgentStatus(policyId?: string, options?: RequestOptions) { isLoading: agentStatusRequest.isLoading, data: agentStatusRequest.data, error: agentStatusRequest.error, - refreshAgentStatus: () => agentStatusRequest.sendRequest, + refreshAgentStatus: () => agentStatusRequest.resendRequest, }; } diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/list_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/list_page/index.tsx index 361b1c33f1a0..fb963dc67ae1 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/list_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/agent_policy/list_page/index.tsx @@ -108,7 +108,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { ); // Fetch agent policies - const { isLoading, data: agentPolicyData, sendRequest } = useGetAgentPolicies({ + const { isLoading, data: agentPolicyData, resendRequest } = useGetAgentPolicies({ page: pagination.currentPage, perPage: pagination.pageSize, sortField: sorting?.field, @@ -204,7 +204,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { render: (agentPolicy: AgentPolicy) => ( sendRequest()} + onCopySuccess={() => resendRequest()} /> ), }, @@ -218,7 +218,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { } return cols; - }, [getHref, isFleetEnabled, sendRequest]); + }, [getHref, isFleetEnabled, resendRequest]); const createAgentPolicyButton = useMemo( () => ( @@ -270,7 +270,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { { setIsCreateAgentPolicyFlyoutOpen(false); - sendRequest(); + resendRequest(); }} /> ) : null} @@ -289,7 +289,7 @@ export const AgentPolicyListPage: React.FunctionComponent<{}> = () => { />
- sendRequest()}> + resendRequest()}> = () => { const { pagination, pageSizeOptions } = usePagination(); // Fetch data streams - const { isLoading, data: dataStreamsData, sendRequest } = useGetDataStreams(); + const { isLoading, data: dataStreamsData, resendRequest } = useGetDataStreams(); // Some policies retrieved, set up table props const columns = useMemo(() => { @@ -241,7 +241,7 @@ export const DataStreamListPage: React.FunctionComponent<{}> = () => { key="reloadButton" color="primary" iconType="refresh" - onClick={() => sendRequest()} + onClick={() => resendRequest()} > = { dashboard: 'Dashboard', ilm_policy: 'ILM Policy', ingest_pipeline: 'Ingest Pipeline', + transform: 'Transform', 'index-pattern': 'Index Pattern', index_template: 'Index Template', component_template: 'Component Template', diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/screenshots.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/screenshots.tsx index d8388a71556d..6326e9072be8 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/screenshots.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/epm/screens/detail/screenshots.tsx @@ -75,7 +75,7 @@ export function Screenshots(props: ScreenshotProps) { set image to same width. Will need to update if size changes. */} = ({ ag [key: string]: JSX.Element; }>({}); - const { isLoading, data, sendRequest } = useGetOneAgentEvents(agent.id, { + const { isLoading, data, resendRequest } = useGetOneAgentEvents(agent.id, { page: pagination.currentPage, perPage: pagination.pageSize, kuery: search && search.trim() !== '' ? search.trim() : undefined, }); - const refresh = () => sendRequest(); + const refresh = () => resendRequest(); const total = data ? data.total : 0; const list = data ? data.list : []; diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/index.tsx index 219b343eba41..fe0781f4a240 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_details_page/index.tsx @@ -51,7 +51,7 @@ export const AgentDetailsPage: React.FunctionComponent = () => { isInitialRequest, error, data: agentData, - sendRequest: sendAgentRequest, + resendRequest: sendAgentRequest, } = useGetOneAgent(agentId, { pollIntervalMs: 5000, }); diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx index 9548340df5b3..46f7ffb85b21 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/agent_list_page/index.tsx @@ -344,7 +344,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { return ( agentsRequest.sendRequest()} + refresh={() => agentsRequest.resendRequest()} onReassignClick={() => setAgentToReassignId(agent.id)} /> ); @@ -394,7 +394,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { agent={agentToReassign} onClose={() => { setAgentToReassignId(undefined); - agentsRequest.sendRequest(); + agentsRequest.resendRequest(); }} /> diff --git a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/enrollment_token_list_page/index.tsx b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/enrollment_token_list_page/index.tsx index b3a4938b2231..d85a6e8b5b83 100644 --- a/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/enrollment_token_list_page/index.tsx +++ b/x-pack/plugins/ingest_manager/public/applications/ingest_manager/sections/fleet/enrollment_token_list_page/index.tsx @@ -244,7 +244,10 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { render: (_: any, apiKey: EnrollmentAPIKey) => { return ( apiKey.active && ( - enrollmentAPIKeysRequest.sendRequest()} /> + enrollmentAPIKeysRequest.resendRequest()} + /> ) ); }, @@ -258,7 +261,7 @@ export const EnrollmentTokenListPage: React.FunctionComponent<{}> = () => { agentPolicies={agentPolicies} onClose={() => { setFlyoutOpen(false); - enrollmentAPIKeysRequest.sendRequest(); + enrollmentAPIKeysRequest.resendRequest(); }} /> )} diff --git a/x-pack/plugins/ingest_manager/server/errors.test.ts b/x-pack/plugins/ingest_manager/server/errors/handlers.test.ts similarity index 73% rename from x-pack/plugins/ingest_manager/server/errors.test.ts rename to x-pack/plugins/ingest_manager/server/errors/handlers.test.ts index 70e3a3b4150a..361386a86d54 100644 --- a/x-pack/plugins/ingest_manager/server/errors.test.ts +++ b/x-pack/plugins/ingest_manager/server/errors/handlers.test.ts @@ -5,16 +5,19 @@ */ import Boom from 'boom'; +import { errors } from 'elasticsearch'; import { httpServerMock } from 'src/core/server/mocks'; -import { createAppContextStartContractMock } from './mocks'; - +import { createAppContextStartContractMock } from '../mocks'; +import { appContextService } from '../services'; import { IngestManagerError, RegistryError, PackageNotFoundError, defaultIngestErrorHandler, -} from './errors'; -import { appContextService } from './services'; +} from './index'; + +const LegacyESErrors = errors as Record; +type ITestEsErrorsFnParams = [errorCode: string, error: any, expectedMessage: string]; describe('defaultIngestErrorHandler', () => { let mockContract: ReturnType; @@ -29,6 +32,55 @@ describe('defaultIngestErrorHandler', () => { appContextService.stop(); }); + async function testEsErrorsFn(...args: ITestEsErrorsFnParams) { + const [, error, expectedMessage] = args; + jest.clearAllMocks(); + const response = httpServerMock.createResponseFactory(); + await defaultIngestErrorHandler({ error, response }); + + // response + expect(response.ok).toHaveBeenCalledTimes(0); + expect(response.customError).toHaveBeenCalledTimes(1); + expect(response.customError).toHaveBeenCalledWith({ + statusCode: error.status, + body: { message: expectedMessage }, + }); + + // logging + expect(mockContract.logger?.error).toHaveBeenCalledTimes(1); + expect(mockContract.logger?.error).toHaveBeenCalledWith(expectedMessage); + } + + describe('use the HTTP error status code provided by LegacyESErrors', () => { + const statusCodes = Object.keys(LegacyESErrors).filter((key) => /^\d+$/.test(key)); + const errorCodes = statusCodes.filter((key) => parseInt(key, 10) >= 400); + const casesWithPathResponse: ITestEsErrorsFnParams[] = errorCodes.map((errorCode) => [ + errorCode, + new LegacyESErrors[errorCode]('the root message', { + path: '/path/to/call', + response: 'response is here', + }), + 'the root message response from /path/to/call: response is here', + ]); + const casesWithOtherMeta: ITestEsErrorsFnParams[] = errorCodes.map((errorCode) => [ + errorCode, + new LegacyESErrors[errorCode]('the root message', { + other: '/path/to/call', + props: 'response is here', + }), + 'the root message', + ]); + const casesWithoutMeta: ITestEsErrorsFnParams[] = errorCodes.map((errorCode) => [ + errorCode, + new LegacyESErrors[errorCode]('some message'), + 'some message', + ]); + + test.each(casesWithPathResponse)('%d - with path & response', testEsErrorsFn); + test.each(casesWithOtherMeta)('%d - with other metadata', testEsErrorsFn); + test.each(casesWithoutMeta)('%d - without metadata', testEsErrorsFn); + }); + describe('IngestManagerError', () => { it('502: RegistryError', async () => { const error = new RegistryError('xyz'); diff --git a/x-pack/plugins/ingest_manager/server/errors.ts b/x-pack/plugins/ingest_manager/server/errors/handlers.ts similarity index 60% rename from x-pack/plugins/ingest_manager/server/errors.ts rename to x-pack/plugins/ingest_manager/server/errors/handlers.ts index 9829a4de23d7..9f776565cf26 100644 --- a/x-pack/plugins/ingest_manager/server/errors.ts +++ b/x-pack/plugins/ingest_manager/server/errors/handlers.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -/* eslint-disable max-classes-per-file */ import Boom, { isBoom } from 'boom'; import { RequestHandlerContext, @@ -12,25 +11,39 @@ import { IKibanaResponse, KibanaResponseFactory, } from 'src/core/server'; -import { appContextService } from './services'; +import { errors as LegacyESErrors } from 'elasticsearch'; +import { appContextService } from '../services'; +import { IngestManagerError, RegistryError, PackageNotFoundError } from './index'; type IngestErrorHandler = ( params: IngestErrorHandlerParams ) => IKibanaResponse | Promise; - interface IngestErrorHandlerParams { error: IngestManagerError | Boom | Error; response: KibanaResponseFactory; request?: KibanaRequest; context?: RequestHandlerContext; } +// unsure if this is correct. would prefer to use something "official" +// this type is based on BadRequest values observed while debugging https://github.com/elastic/kibana/issues/75862 -export class IngestManagerError extends Error { - constructor(message?: string) { - super(message); - this.name = this.constructor.name; // for stack traces - } +interface LegacyESClientError { + message: string; + stack: string; + status: number; + displayName: string; + path?: string; + query?: string | undefined; + body?: { + error: object; + status: number; + }; + statusCode?: number; + response?: string; } +export const isLegacyESClientError = (error: any): error is LegacyESClientError => { + return error instanceof LegacyESErrors._Abstract; +}; const getHTTPResponseCode = (error: IngestManagerError): number => { if (error instanceof RegistryError) { @@ -48,6 +61,22 @@ export const defaultIngestErrorHandler: IngestErrorHandler = async ({ response, }: IngestErrorHandlerParams): Promise => { const logger = appContextService.getLogger(); + if (isLegacyESClientError(error)) { + // there was a problem communicating with ES (e.g. via `callCluster`) + // only log the message + const message = + error?.path && error?.response + ? // if possible, return the failing endpoint and its response + `${error.message} response from ${error.path}: ${error.response}` + : error.message; + + logger.error(message); + + return response.customError({ + statusCode: error?.statusCode || error.status, + body: { message }, + }); + } // our "expected" errors if (error instanceof IngestManagerError) { @@ -76,9 +105,3 @@ export const defaultIngestErrorHandler: IngestErrorHandler = async ({ body: { message: error.message }, }); }; - -export class RegistryError extends IngestManagerError {} -export class RegistryConnectionError extends RegistryError {} -export class RegistryResponseError extends RegistryError {} -export class PackageNotFoundError extends IngestManagerError {} -export class PackageOutdatedError extends IngestManagerError {} diff --git a/x-pack/plugins/ingest_manager/server/errors/index.ts b/x-pack/plugins/ingest_manager/server/errors/index.ts new file mode 100644 index 000000000000..5e36a2ec9a88 --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/errors/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/* eslint-disable max-classes-per-file */ +export { defaultIngestErrorHandler } from './handlers'; + +export class IngestManagerError extends Error { + constructor(message?: string) { + super(message); + this.name = this.constructor.name; // for stack traces + } +} +export class RegistryError extends IngestManagerError {} +export class RegistryConnectionError extends RegistryError {} +export class RegistryResponseError extends RegistryError {} +export class PackageNotFoundError extends IngestManagerError {} +export class PackageOutdatedError extends IngestManagerError {} diff --git a/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts b/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts index 6d7252ffec41..385e256933c1 100644 --- a/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts +++ b/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts @@ -34,6 +34,7 @@ import { } from '../../services/epm/packages'; import { IngestManagerError, defaultIngestErrorHandler } from '../../errors'; import { splitPkgKey } from '../../services/epm/registry'; +import { getInstallType } from '../../services/epm/packages/install'; export const getCategoriesHandler: RequestHandler< undefined, @@ -138,6 +139,8 @@ export const installPackageHandler: RequestHandler< const callCluster = context.core.elasticsearch.legacy.client.callAsCurrentUser; const { pkgkey } = request.params; const { pkgName, pkgVersion } = splitPkgKey(pkgkey); + const installedPkg = await getInstallationObject({ savedObjectsClient, pkgName }); + const installType = getInstallType({ pkgVersion, installedPkg }); try { const res = await installPackage({ savedObjectsClient, @@ -156,15 +159,25 @@ export const installPackageHandler: RequestHandler< if (e instanceof IngestManagerError) { return defaultResult; } - // if there is an unknown server error, uninstall any package assets + + // if there is an unknown server error, uninstall any package assets or reinstall the previous version if update try { - const installedPkg = await getInstallationObject({ savedObjectsClient, pkgName }); - const isUpdate = installedPkg && installedPkg.attributes.version < pkgVersion ? true : false; - if (!isUpdate) { + if (installType === 'install' || installType === 'reinstall') { + logger.error(`uninstalling ${pkgkey} after error installing`); await removeInstallation({ savedObjectsClient, pkgkey, callCluster }); } + if (installType === 'update') { + // @ts-ignore getInstallType ensures we have installedPkg + const prevVersion = `${pkgName}-${installedPkg.attributes.version}`; + logger.error(`rolling back to ${prevVersion} after error installing ${pkgkey}`); + await installPackage({ + savedObjectsClient, + pkgkey: prevVersion, + callCluster, + }); + } } catch (error) { - logger.error(`could not remove failed installation ${error}`); + logger.error(`failed to uninstall or rollback package after installation error ${error}`); } return defaultResult; } diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/install.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/install.ts index 44e4eddfbbe6..878c6ea8f280 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/install.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/ingest_pipeline/install.ts @@ -156,7 +156,12 @@ async function installPipeline({ body: pipeline.contentForInstallation, }; if (pipeline.extension === 'yml') { - callClusterParams.headers = { ['Content-Type']: 'application/yaml' }; + callClusterParams.headers = { + // pipeline is YAML + 'Content-Type': 'application/yaml', + // but we want JSON responses (to extract error messages, status code, or other metadata) + Accept: 'application/json', + }; } // This uses the catch-all endpoint 'transport.request' because we have to explicitly diff --git a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.d.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/common.ts similarity index 56% rename from x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.d.ts rename to x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/common.ts index a23e715a0829..46f36dba9674 100644 --- a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.d.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/common.ts @@ -4,9 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { LayerDescriptor } from '../../../common/descriptor_types'; +import * as Registry from '../../registry'; -export function getInitialLayers( - layerListJSON?: string, - initialLayers?: LayerDescriptor[] -): LayerDescriptor[]; +export const getAsset = (path: string): Buffer => { + return Registry.getAsset(path); +}; diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/install.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/install.ts new file mode 100644 index 000000000000..1e58319183c7 --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/install.ts @@ -0,0 +1,165 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SavedObjectsClientContract } from 'kibana/server'; + +import { saveInstalledEsRefs } from '../../packages/install'; +import * as Registry from '../../registry'; +import { + Dataset, + ElasticsearchAssetType, + EsAssetReference, + RegistryPackage, +} from '../../../../../common/types/models'; +import { CallESAsCurrentUser } from '../../../../types'; +import { getInstallation } from '../../packages'; +import { deleteTransforms, deleteTransformRefs } from './remove'; +import { getAsset } from './common'; + +interface TransformInstallation { + installationName: string; + content: string; +} + +interface TransformPathDataset { + path: string; + dataset: Dataset; +} + +export const installTransformForDataset = async ( + registryPackage: RegistryPackage, + paths: string[], + callCluster: CallESAsCurrentUser, + savedObjectsClient: SavedObjectsClientContract +) => { + const installation = await getInstallation({ savedObjectsClient, pkgName: registryPackage.name }); + let previousInstalledTransformEsAssets: EsAssetReference[] = []; + if (installation) { + previousInstalledTransformEsAssets = installation.installed_es.filter( + ({ type, id }) => type === ElasticsearchAssetType.transform + ); + } + + // delete all previous transform + await deleteTransforms( + callCluster, + previousInstalledTransformEsAssets.map((asset) => asset.id) + ); + // install the latest dataset + const datasets = registryPackage.datasets; + if (!datasets?.length) return []; + const installNameSuffix = `${registryPackage.version}`; + + const transformPaths = paths.filter((path) => isTransform(path)); + let installedTransforms: EsAssetReference[] = []; + if (transformPaths.length > 0) { + const transformPathDatasets = datasets.reduce((acc, dataset) => { + transformPaths.forEach((path) => { + if (isDatasetTransform(path, dataset.path)) { + acc.push({ path, dataset }); + } + }); + return acc; + }, []); + + const transformRefs = transformPathDatasets.reduce( + (acc, transformPathDataset) => { + if (transformPathDataset) { + acc.push({ + id: getTransformNameForInstallation(transformPathDataset, installNameSuffix), + type: ElasticsearchAssetType.transform, + }); + } + return acc; + }, + [] + ); + + // get and save transform refs before installing transforms + await saveInstalledEsRefs(savedObjectsClient, registryPackage.name, transformRefs); + + const transforms: TransformInstallation[] = transformPathDatasets.map( + (transformPathDataset: TransformPathDataset) => { + return { + installationName: getTransformNameForInstallation( + transformPathDataset, + installNameSuffix + ), + content: getAsset(transformPathDataset.path).toString('utf-8'), + }; + } + ); + + const installationPromises = transforms.map(async (transform) => { + return installTransform({ callCluster, transform }); + }); + + installedTransforms = await Promise.all(installationPromises).then((results) => results.flat()); + } + + if (previousInstalledTransformEsAssets.length > 0) { + const currentInstallation = await getInstallation({ + savedObjectsClient, + pkgName: registryPackage.name, + }); + + // remove the saved object reference + await deleteTransformRefs( + savedObjectsClient, + currentInstallation?.installed_es || [], + registryPackage.name, + previousInstalledTransformEsAssets.map((asset) => asset.id), + installedTransforms.map((installed) => installed.id) + ); + } + return installedTransforms; +}; + +const isTransform = (path: string) => { + const pathParts = Registry.pathParts(path); + return pathParts.type === ElasticsearchAssetType.transform; +}; + +const isDatasetTransform = (path: string, datasetName: string) => { + const pathParts = Registry.pathParts(path); + return ( + !path.endsWith('/') && + pathParts.type === ElasticsearchAssetType.transform && + pathParts.dataset !== undefined && + datasetName === pathParts.dataset + ); +}; + +async function installTransform({ + callCluster, + transform, +}: { + callCluster: CallESAsCurrentUser; + transform: TransformInstallation; +}): Promise { + // defer validation on put if the source index is not available + await callCluster('transport.request', { + method: 'PUT', + path: `_transform/${transform.installationName}`, + query: 'defer_validation=true', + body: transform.content, + }); + + await callCluster('transport.request', { + method: 'POST', + path: `_transform/${transform.installationName}/_start`, + }); + + return { id: transform.installationName, type: ElasticsearchAssetType.transform }; +} + +const getTransformNameForInstallation = ( + transformDataset: TransformPathDataset, + suffix: string +) => { + const filename = transformDataset?.path.split('/')?.pop()?.split('.')[0]; + return `${transformDataset.dataset.type}-${transformDataset.dataset.name}-${filename}-${suffix}`; +}; diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/remove.test.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/remove.test.ts new file mode 100644 index 000000000000..3f85ee9b550b --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/remove.test.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SavedObjectsClientContract } from 'kibana/server'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { savedObjectsClientMock } from '../../../../../../../../src/core/server/saved_objects/service/saved_objects_client.mock'; +import { deleteTransformRefs } from './remove'; +import { EsAssetReference } from '../../../../../common/types/models'; + +describe('test transform install', () => { + let savedObjectsClient: jest.Mocked; + beforeEach(() => { + savedObjectsClient = savedObjectsClientMock.create(); + }); + + test('can delete transform ref and handle duplicate when previous version and current version are the same', async () => { + await deleteTransformRefs( + savedObjectsClient, + [ + { id: 'metrics-endpoint.policy-0.16.0-dev.0', type: 'ingest_pipeline' }, + { id: 'metrics-endpoint.metadata-current-default-0.16.0-dev.0', type: 'transform' }, + ] as EsAssetReference[], + 'endpoint', + ['metrics-endpoint.metadata-current-default-0.16.0-dev.0'], + ['metrics-endpoint.metadata-current-default-0.16.0-dev.0'] + ); + expect(savedObjectsClient.update.mock.calls).toEqual([ + [ + 'epm-packages', + 'endpoint', + { + installed_es: [ + { id: 'metrics-endpoint.policy-0.16.0-dev.0', type: 'ingest_pipeline' }, + { id: 'metrics-endpoint.metadata-current-default-0.16.0-dev.0', type: 'transform' }, + ], + }, + ], + ]); + }); + + test('can delete transform ref when previous version and current version are not the same', async () => { + await deleteTransformRefs( + savedObjectsClient, + [ + { id: 'metrics-endpoint.policy-0.16.0-dev.0', type: 'ingest_pipeline' }, + { id: 'metrics-endpoint.metadata-current-default-0.16.0-dev.0', type: 'transform' }, + ] as EsAssetReference[], + 'endpoint', + ['metrics-endpoint.metadata-current-default-0.15.0-dev.0'], + ['metrics-endpoint.metadata-current-default-0.16.0-dev.0'] + ); + + expect(savedObjectsClient.update.mock.calls).toEqual([ + [ + 'epm-packages', + 'endpoint', + { + installed_es: [ + { id: 'metrics-endpoint.policy-0.16.0-dev.0', type: 'ingest_pipeline' }, + { id: 'metrics-endpoint.metadata-current-default-0.16.0-dev.0', type: 'transform' }, + ], + }, + ], + ]); + }); +}); diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/remove.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/remove.ts new file mode 100644 index 000000000000..5c9d3e284620 --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/remove.ts @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { SavedObjectsClientContract } from 'kibana/server'; +import { CallESAsCurrentUser, ElasticsearchAssetType, EsAssetReference } from '../../../../types'; +import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common/constants'; + +export const stopTransforms = async (transformIds: string[], callCluster: CallESAsCurrentUser) => { + for (const transformId of transformIds) { + await callCluster('transport.request', { + method: 'POST', + path: `_transform/${transformId}/_stop`, + query: 'force=true', + ignore: [404], + }); + } +}; + +export const deleteTransforms = async ( + callCluster: CallESAsCurrentUser, + transformIds: string[] +) => { + await Promise.all( + transformIds.map(async (transformId) => { + await stopTransforms([transformId], callCluster); + await callCluster('transport.request', { + method: 'DELETE', + query: 'force=true', + path: `_transform/${transformId}`, + ignore: [404], + }); + }) + ); +}; + +export const deleteTransformRefs = async ( + savedObjectsClient: SavedObjectsClientContract, + installedEsAssets: EsAssetReference[], + pkgName: string, + installedEsIdToRemove: string[], + currentInstalledEsTransformIds: string[] +) => { + const seen = new Set(); + const filteredAssets = installedEsAssets.filter(({ type, id }) => { + if (type !== ElasticsearchAssetType.transform) return true; + const add = + (currentInstalledEsTransformIds.includes(id) || !installedEsIdToRemove.includes(id)) && + !seen.has(id); + seen.add(id); + return add; + }); + return savedObjectsClient.update(PACKAGES_SAVED_OBJECT_TYPE, pkgName, { + installed_es: filteredAssets, + }); +}; diff --git a/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/transform.test.ts b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/transform.test.ts new file mode 100644 index 000000000000..0b66077b8699 --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/services/epm/elasticsearch/transform/transform.test.ts @@ -0,0 +1,420 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +jest.mock('../../packages/get', () => { + return { getInstallation: jest.fn(), getInstallationObject: jest.fn() }; +}); + +jest.mock('./common', () => { + return { + getAsset: jest.fn(), + }; +}); + +import { installTransformForDataset } from './install'; +import { ILegacyScopedClusterClient, SavedObject, SavedObjectsClientContract } from 'kibana/server'; +import { ElasticsearchAssetType, Installation, RegistryPackage } from '../../../../types'; +import { getInstallation, getInstallationObject } from '../../packages'; +import { getAsset } from './common'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { savedObjectsClientMock } from '../../../../../../../../src/core/server/saved_objects/service/saved_objects_client.mock'; + +describe('test transform install', () => { + let legacyScopedClusterClient: jest.Mocked; + let savedObjectsClient: jest.Mocked; + beforeEach(() => { + legacyScopedClusterClient = { + callAsInternalUser: jest.fn(), + callAsCurrentUser: jest.fn(), + }; + (getInstallation as jest.MockedFunction).mockReset(); + (getInstallationObject as jest.MockedFunction).mockReset(); + savedObjectsClient = savedObjectsClientMock.create(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + test('can install new versions and removes older version', async () => { + const previousInstallation: Installation = ({ + installed_es: [ + { + id: 'metrics-endpoint.policy-0.16.0-dev.0', + type: ElasticsearchAssetType.ingestPipeline, + }, + { + id: 'metrics-endpoint.metadata_current-default-0.15.0-dev.0', + type: ElasticsearchAssetType.transform, + }, + ], + } as unknown) as Installation; + + const currentInstallation: Installation = ({ + installed_es: [ + { + id: 'metrics-endpoint.policy-0.16.0-dev.0', + type: ElasticsearchAssetType.ingestPipeline, + }, + { + id: 'metrics-endpoint.metadata_current-default-0.15.0-dev.0', + type: ElasticsearchAssetType.transform, + }, + { + id: 'metrics-endpoint.metadata_current-default-0.16.0-dev.0', + type: ElasticsearchAssetType.transform, + }, + { + id: 'metrics-endpoint.metadata-default-0.16.0-dev.0', + type: ElasticsearchAssetType.transform, + }, + ], + } as unknown) as Installation; + (getAsset as jest.MockedFunction) + .mockReturnValueOnce(Buffer.from('{"content": "data"}', 'utf8')) + .mockReturnValueOnce(Buffer.from('{"content": "data"}', 'utf8')); + + (getInstallation as jest.MockedFunction) + .mockReturnValueOnce(Promise.resolve(previousInstallation)) + .mockReturnValueOnce(Promise.resolve(currentInstallation)); + + (getInstallationObject as jest.MockedFunction< + typeof getInstallationObject + >).mockReturnValueOnce( + Promise.resolve(({ + attributes: { + installed_es: previousInstallation.installed_es, + }, + } as unknown) as SavedObject) + ); + + await installTransformForDataset( + ({ + name: 'endpoint', + version: '0.16.0-dev.0', + datasets: [ + { + type: 'metrics', + name: 'endpoint.metadata', + title: 'Endpoint Metadata', + release: 'experimental', + package: 'endpoint', + ingest_pipeline: 'default', + elasticsearch: { + 'index_template.mappings': { + dynamic: false, + }, + }, + path: 'metadata', + }, + { + type: 'metrics', + name: 'endpoint.metadata_current', + title: 'Endpoint Metadata Current', + release: 'experimental', + package: 'endpoint', + ingest_pipeline: 'default', + elasticsearch: { + 'index_template.mappings': { + dynamic: false, + }, + }, + path: 'metadata_current', + }, + ], + } as unknown) as RegistryPackage, + [ + 'endpoint-0.16.0-dev.0/dataset/policy/elasticsearch/ingest_pipeline/default.json', + 'endpoint-0.16.0-dev.0/dataset/metadata/elasticsearch/transform/default.json', + 'endpoint-0.16.0-dev.0/dataset/metadata_current/elasticsearch/transform/default.json', + ], + legacyScopedClusterClient.callAsCurrentUser, + savedObjectsClient + ); + + expect(legacyScopedClusterClient.callAsCurrentUser.mock.calls).toEqual([ + [ + 'transport.request', + { + method: 'POST', + path: '_transform/metrics-endpoint.metadata_current-default-0.15.0-dev.0/_stop', + query: 'force=true', + ignore: [404], + }, + ], + [ + 'transport.request', + { + method: 'DELETE', + query: 'force=true', + path: '_transform/metrics-endpoint.metadata_current-default-0.15.0-dev.0', + ignore: [404], + }, + ], + [ + 'transport.request', + { + method: 'PUT', + path: '_transform/metrics-endpoint.metadata-default-0.16.0-dev.0', + query: 'defer_validation=true', + body: '{"content": "data"}', + }, + ], + [ + 'transport.request', + { + method: 'PUT', + path: '_transform/metrics-endpoint.metadata_current-default-0.16.0-dev.0', + query: 'defer_validation=true', + body: '{"content": "data"}', + }, + ], + [ + 'transport.request', + { + method: 'POST', + path: '_transform/metrics-endpoint.metadata-default-0.16.0-dev.0/_start', + }, + ], + [ + 'transport.request', + { + method: 'POST', + path: '_transform/metrics-endpoint.metadata_current-default-0.16.0-dev.0/_start', + }, + ], + ]); + + expect(savedObjectsClient.update.mock.calls).toEqual([ + [ + 'epm-packages', + 'endpoint', + { + installed_es: [ + { + id: 'metrics-endpoint.policy-0.16.0-dev.0', + type: 'ingest_pipeline', + }, + { + id: 'metrics-endpoint.metadata_current-default-0.15.0-dev.0', + type: 'transform', + }, + { + id: 'metrics-endpoint.metadata-default-0.16.0-dev.0', + type: 'transform', + }, + { + id: 'metrics-endpoint.metadata_current-default-0.16.0-dev.0', + type: 'transform', + }, + ], + }, + ], + [ + 'epm-packages', + 'endpoint', + { + installed_es: [ + { + id: 'metrics-endpoint.policy-0.16.0-dev.0', + type: 'ingest_pipeline', + }, + { + id: 'metrics-endpoint.metadata_current-default-0.16.0-dev.0', + type: 'transform', + }, + { + id: 'metrics-endpoint.metadata-default-0.16.0-dev.0', + type: 'transform', + }, + ], + }, + ], + ]); + }); + + test('can install new version and when no older version', async () => { + const previousInstallation: Installation = ({ + installed_es: [], + } as unknown) as Installation; + + const currentInstallation: Installation = ({ + installed_es: [ + { + id: 'metrics-endpoint.metadata-current-default-0.16.0-dev.0', + type: ElasticsearchAssetType.transform, + }, + ], + } as unknown) as Installation; + (getAsset as jest.MockedFunction).mockReturnValueOnce( + Buffer.from('{"content": "data"}', 'utf8') + ); + (getInstallation as jest.MockedFunction) + .mockReturnValueOnce(Promise.resolve(previousInstallation)) + .mockReturnValueOnce(Promise.resolve(currentInstallation)); + + (getInstallationObject as jest.MockedFunction< + typeof getInstallationObject + >).mockReturnValueOnce( + Promise.resolve(({ attributes: { installed_es: [] } } as unknown) as SavedObject< + Installation + >) + ); + legacyScopedClusterClient.callAsCurrentUser = jest.fn(); + await installTransformForDataset( + ({ + name: 'endpoint', + version: '0.16.0-dev.0', + datasets: [ + { + type: 'metrics', + name: 'endpoint.metadata_current', + title: 'Endpoint Metadata', + release: 'experimental', + package: 'endpoint', + ingest_pipeline: 'default', + elasticsearch: { + 'index_template.mappings': { + dynamic: false, + }, + }, + path: 'metadata_current', + }, + ], + } as unknown) as RegistryPackage, + ['endpoint-0.16.0-dev.0/dataset/metadata_current/elasticsearch/transform/default.json'], + legacyScopedClusterClient.callAsCurrentUser, + savedObjectsClient + ); + + expect(legacyScopedClusterClient.callAsCurrentUser.mock.calls).toEqual([ + [ + 'transport.request', + { + method: 'PUT', + path: '_transform/metrics-endpoint.metadata_current-default-0.16.0-dev.0', + query: 'defer_validation=true', + body: '{"content": "data"}', + }, + ], + [ + 'transport.request', + { + method: 'POST', + path: '_transform/metrics-endpoint.metadata_current-default-0.16.0-dev.0/_start', + }, + ], + ]); + expect(savedObjectsClient.update.mock.calls).toEqual([ + [ + 'epm-packages', + 'endpoint', + { + installed_es: [ + { id: 'metrics-endpoint.metadata_current-default-0.16.0-dev.0', type: 'transform' }, + ], + }, + ], + ]); + }); + + test('can removes older version when no new install in package', async () => { + const previousInstallation: Installation = ({ + installed_es: [ + { + id: 'metrics-endpoint.metadata-current-default-0.15.0-dev.0', + type: ElasticsearchAssetType.transform, + }, + ], + } as unknown) as Installation; + + const currentInstallation: Installation = ({ + installed_es: [], + } as unknown) as Installation; + + (getInstallation as jest.MockedFunction) + .mockReturnValueOnce(Promise.resolve(previousInstallation)) + .mockReturnValueOnce(Promise.resolve(currentInstallation)); + + (getInstallationObject as jest.MockedFunction< + typeof getInstallationObject + >).mockReturnValueOnce( + Promise.resolve(({ + attributes: { installed_es: currentInstallation.installed_es }, + } as unknown) as SavedObject) + ); + + await installTransformForDataset( + ({ + name: 'endpoint', + version: '0.16.0-dev.0', + datasets: [ + { + type: 'metrics', + name: 'endpoint.metadata', + title: 'Endpoint Metadata', + release: 'experimental', + package: 'endpoint', + ingest_pipeline: 'default', + elasticsearch: { + 'index_template.mappings': { + dynamic: false, + }, + }, + path: 'metadata', + }, + { + type: 'metrics', + name: 'endpoint.metadata_current', + title: 'Endpoint Metadata Current', + release: 'experimental', + package: 'endpoint', + ingest_pipeline: 'default', + elasticsearch: { + 'index_template.mappings': { + dynamic: false, + }, + }, + path: 'metadata_current', + }, + ], + } as unknown) as RegistryPackage, + [], + legacyScopedClusterClient.callAsCurrentUser, + savedObjectsClient + ); + + expect(legacyScopedClusterClient.callAsCurrentUser.mock.calls).toEqual([ + [ + 'transport.request', + { + ignore: [404], + method: 'POST', + path: '_transform/metrics-endpoint.metadata-current-default-0.15.0-dev.0/_stop', + query: 'force=true', + }, + ], + [ + 'transport.request', + { + ignore: [404], + method: 'DELETE', + path: '_transform/metrics-endpoint.metadata-current-default-0.15.0-dev.0', + query: 'force=true', + }, + ], + ]); + expect(savedObjectsClient.update.mock.calls).toEqual([ + [ + 'epm-packages', + 'endpoint', + { + installed_es: [], + }, + ], + ]); + }); +}); diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/install.test.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/install.test.ts new file mode 100644 index 000000000000..2f60c74d3514 --- /dev/null +++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/install.test.ts @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ElasticsearchAssetType, Installation, KibanaAssetType } from '../../../types'; +import { SavedObject } from 'src/core/server'; +import { getInstallType } from './install'; + +const mockInstallation: SavedObject = { + id: 'test-pkg', + references: [], + type: 'epm-packages', + attributes: { + id: 'test-pkg', + installed_kibana: [{ type: KibanaAssetType.dashboard, id: 'dashboard-1' }], + installed_es: [{ type: ElasticsearchAssetType.ingestPipeline, id: 'pipeline' }], + es_index_patterns: { pattern: 'pattern-name' }, + name: 'test packagek', + version: '1.0.0', + install_status: 'installed', + install_version: '1.0.0', + install_started_at: new Date().toISOString(), + }, +}; +const mockInstallationUpdateFail: SavedObject = { + id: 'test-pkg', + references: [], + type: 'epm-packages', + attributes: { + id: 'test-pkg', + installed_kibana: [{ type: KibanaAssetType.dashboard, id: 'dashboard-1' }], + installed_es: [{ type: ElasticsearchAssetType.ingestPipeline, id: 'pipeline' }], + es_index_patterns: { pattern: 'pattern-name' }, + name: 'test packagek', + version: '1.0.0', + install_status: 'installing', + install_version: '1.0.1', + install_started_at: new Date().toISOString(), + }, +}; +describe('install', () => { + describe('getInstallType', () => { + it('should return correct type when installing and no other version is currently installed', () => { + const installTypeInstall = getInstallType({ pkgVersion: '1.0.0', installedPkg: undefined }); + expect(installTypeInstall).toBe('install'); + + // @ts-expect-error can only be 'install' if no installedPkg given + expect(installTypeInstall === 'update').toBe(false); + // @ts-expect-error can only be 'install' if no installedPkg given + expect(installTypeInstall === 'reinstall').toBe(false); + // @ts-expect-error can only be 'install' if no installedPkg given + expect(installTypeInstall === 'reupdate').toBe(false); + // @ts-expect-error can only be 'install' if no installedPkg given + expect(installTypeInstall === 'rollback').toBe(false); + }); + + it('should return correct type when installing the same version', () => { + const installTypeReinstall = getInstallType({ + pkgVersion: '1.0.0', + installedPkg: mockInstallation, + }); + expect(installTypeReinstall).toBe('reinstall'); + + // @ts-expect-error cannot be 'install' if given installedPkg + expect(installTypeReinstall === 'install').toBe(false); + }); + + it('should return correct type when moving from one version to another', () => { + const installTypeUpdate = getInstallType({ + pkgVersion: '1.0.1', + installedPkg: mockInstallation, + }); + expect(installTypeUpdate).toBe('update'); + + // @ts-expect-error cannot be 'install' if given installedPkg + expect(installTypeUpdate === 'install').toBe(false); + }); + + it('should return correct type when update fails and trys again', () => { + const installTypeReupdate = getInstallType({ + pkgVersion: '1.0.1', + installedPkg: mockInstallationUpdateFail, + }); + expect(installTypeReupdate).toBe('reupdate'); + + // @ts-expect-error cannot be 'install' if given installedPkg + expect(installTypeReupdate === 'install').toBe(false); + }); + + it('should return correct type when attempting to rollback from a failed update', () => { + const installTypeRollback = getInstallType({ + pkgVersion: '1.0.0', + installedPkg: mockInstallationUpdateFail, + }); + expect(installTypeRollback).toBe('rollback'); + + // @ts-expect-error cannot be 'install' if given installedPkg + expect(installTypeRollback === 'install').toBe(false); + }); + }); +}); diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts index e49dbe8f0b5d..54b9c4d3fbb1 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/install.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SavedObjectsClientContract } from 'src/core/server'; +import { SavedObject, SavedObjectsClientContract } from 'src/core/server'; import semver from 'semver'; import { PACKAGES_SAVED_OBJECT_TYPE, MAX_TIME_COMPLETE_INSTALL } from '../../../constants'; import { @@ -16,6 +16,7 @@ import { KibanaAssetReference, EsAssetReference, ElasticsearchAssetType, + InstallType, } from '../../../types'; import { installIndexPatterns } from '../kibana/index_pattern/install'; import * as Registry from '../registry'; @@ -34,6 +35,7 @@ import { updateCurrentWriteIndices } from '../elasticsearch/template/template'; import { deleteKibanaSavedObjectsAssets } from './remove'; import { PackageOutdatedError } from '../../../errors'; import { getPackageSavedObjects } from './get'; +import { installTransformForDataset } from '../elasticsearch/transform/install'; export async function installLatestPackage(options: { savedObjectsClient: SavedObjectsClientContract; @@ -110,11 +112,13 @@ export async function installPackage({ const latestPackage = await Registry.fetchFindLatestPackage(pkgName); // get the currently installed package const installedPkg = await getInstallationObject({ savedObjectsClient, pkgName }); - const reinstall = pkgVersion === installedPkg?.attributes.version; - const reupdate = pkgVersion === installedPkg?.attributes.install_version; - // let the user install if using the force flag or this is a reinstall or reupdate due to intallation interruption - if (semver.lt(pkgVersion, latestPackage.version) && !force && !reinstall && !reupdate) { + const installType = getInstallType({ pkgVersion, installedPkg }); + + // let the user install if using the force flag or needing to reinstall or install a previous version due to failed update + const installOutOfDateVersionOk = + installType === 'reinstall' || installType === 'reupdate' || installType === 'rollback'; + if (semver.lt(pkgVersion, latestPackage.version) && !force && !installOutOfDateVersionOk) { throw new PackageOutdatedError(`${pkgkey} is out-of-date and cannot be installed or updated`); } const paths = await Registry.getArchiveInfo(pkgName, pkgVersion); @@ -188,8 +192,15 @@ export async function installPackage({ // update current backing indices of each data stream await updateCurrentWriteIndices(callCluster, installedTemplates); - // if this is an update, delete the previous version's pipelines - if (installedPkg && !reinstall) { + const installedTransforms = await installTransformForDataset( + registryPackageInfo, + paths, + callCluster, + savedObjectsClient + ); + + // if this is an update or retrying an update, delete the previous version's pipelines + if ((installType === 'update' || installType === 'reupdate') && installedPkg) { await deletePreviousPipelines( callCluster, savedObjectsClient, @@ -197,19 +208,33 @@ export async function installPackage({ installedPkg.attributes.version ); } - + // pipelines from a different version may have installed during a failed update + if (installType === 'rollback' && installedPkg) { + await deletePreviousPipelines( + callCluster, + savedObjectsClient, + pkgName, + installedPkg.attributes.install_version + ); + } const installedTemplateRefs = installedTemplates.map((template) => ({ id: template.templateName, type: ElasticsearchAssetType.indexTemplate, })); await Promise.all([installKibanaAssetsPromise, installIndexPatternPromise]); + // update to newly installed version when all assets are successfully installed if (installedPkg) await updateVersion(savedObjectsClient, pkgName, pkgVersion); await savedObjectsClient.update(PACKAGES_SAVED_OBJECT_TYPE, pkgName, { install_version: pkgVersion, install_status: 'installed', }); - return [...installedKibanaAssetsRefs, ...installedPipelines, ...installedTemplateRefs]; + return [ + ...installedKibanaAssetsRefs, + ...installedPipelines, + ...installedTemplateRefs, + ...installedTransforms, + ]; } const updateVersion = async ( @@ -326,3 +351,38 @@ export async function ensurePackagesCompletedInstall( await Promise.all(installingPromises); return installingPackages; } + +interface NoPkgArgs { + pkgVersion: string; + installedPkg?: undefined; +} + +interface HasPkgArgs { + pkgVersion: string; + installedPkg: SavedObject; +} + +type OnlyInstall = Extract; +type NotInstall = Exclude; + +// overloads +export function getInstallType(args: NoPkgArgs): OnlyInstall; +export function getInstallType(args: HasPkgArgs): NotInstall; +export function getInstallType(args: NoPkgArgs | HasPkgArgs): OnlyInstall | NotInstall; + +// implementation +export function getInstallType(args: NoPkgArgs | HasPkgArgs): OnlyInstall | NotInstall { + const { pkgVersion, installedPkg } = args; + if (!installedPkg) return 'install'; + + const currentPkgVersion = installedPkg.attributes.version; + const lastStartedInstallVersion = installedPkg.attributes.install_version; + + if (pkgVersion === currentPkgVersion && pkgVersion !== lastStartedInstallVersion) + return 'rollback'; + if (pkgVersion === currentPkgVersion) return 'reinstall'; + if (pkgVersion === lastStartedInstallVersion && pkgVersion !== currentPkgVersion) + return 'reupdate'; + if (pkgVersion !== lastStartedInstallVersion && pkgVersion !== currentPkgVersion) return 'update'; + throw new Error('unknown install type'); +} diff --git a/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts b/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts index 71eee1ee82c9..2434ebf27aa5 100644 --- a/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts +++ b/x-pack/plugins/ingest_manager/server/services/epm/packages/remove.ts @@ -6,12 +6,17 @@ import { SavedObjectsClientContract } from 'src/core/server'; import Boom from 'boom'; -import { PACKAGES_SAVED_OBJECT_TYPE, PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../constants'; -import { AssetReference, AssetType, ElasticsearchAssetType } from '../../../types'; -import { CallESAsCurrentUser } from '../../../types'; +import { PACKAGE_POLICY_SAVED_OBJECT_TYPE, PACKAGES_SAVED_OBJECT_TYPE } from '../../../constants'; +import { + AssetReference, + AssetType, + CallESAsCurrentUser, + ElasticsearchAssetType, +} from '../../../types'; import { getInstallation, savedObjectTypes } from './index'; import { deletePipeline } from '../elasticsearch/ingest_pipeline/'; import { installIndexPatterns } from '../kibana/index_pattern/install'; +import { deleteTransforms } from '../elasticsearch/transform/remove'; import { packagePolicyService, appContextService } from '../..'; import { splitPkgKey, deletePackageCache, getArchiveInfo } from '../registry'; @@ -72,6 +77,8 @@ async function deleteAssets( return deletePipeline(callCluster, id); } else if (assetType === ElasticsearchAssetType.indexTemplate) { return deleteTemplate(callCluster, id); + } else if (assetType === ElasticsearchAssetType.transform) { + return deleteTransforms(callCluster, [id]); } }); try { diff --git a/x-pack/plugins/ingest_manager/server/types/index.tsx b/x-pack/plugins/ingest_manager/server/types/index.tsx index e01568cfbb3c..2746dfcd00ce 100644 --- a/x-pack/plugins/ingest_manager/server/types/index.tsx +++ b/x-pack/plugins/ingest_manager/server/types/index.tsx @@ -63,6 +63,7 @@ export { IndexTemplateMappings, Settings, SettingsSOAttributes, + InstallType, // Agent Request types PostAgentEnrollRequest, PostAgentCheckinRequest, diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/kv.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/kv.tsx index f51bf19ad180..4104e8f727ab 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/kv.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/kv.tsx @@ -33,9 +33,15 @@ const fieldsConfig: FieldsConfig = { label: i18n.translate('xpack.ingestPipelines.pipelineEditor.kvForm.fieldSplitFieldLabel', { defaultMessage: 'Field split', }), - helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.kvForm.fieldSplitHelpText', { - defaultMessage: 'Regex pattern for splitting key-value pairs.', - }), + helpText: ( + {'" "'}, + }} + /> + ), validations: [ { validator: emptyField( @@ -52,9 +58,15 @@ const fieldsConfig: FieldsConfig = { label: i18n.translate('xpack.ingestPipelines.pipelineEditor.kvForm.valueSplitFieldLabel', { defaultMessage: 'Value split', }), - helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.kvForm.valueSplitHelpText', { - defaultMessage: 'Regex pattern for splitting the key from the value within a key-value pair.', - }), + helpText: ( + {'"="'}, + }} + /> + ), validations: [ { validator: emptyField( @@ -75,8 +87,7 @@ const fieldsConfig: FieldsConfig = { defaultMessage: 'Include keys', }), helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.kvForm.includeKeysHelpText', { - defaultMessage: - 'List of keys to filter and insert into document. Defaults to including all keys.', + defaultMessage: 'List of extracted keys to include in the output. Defaults to all keys.', }), }, @@ -88,7 +99,7 @@ const fieldsConfig: FieldsConfig = { defaultMessage: 'Exclude keys', }), helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.kvForm.excludeKeysHelpText', { - defaultMessage: 'List of keys to exclude from document.', + defaultMessage: 'List of extracted keys to exclude from the output.', }), }, @@ -99,7 +110,7 @@ const fieldsConfig: FieldsConfig = { defaultMessage: 'Prefix', }), helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.kvForm.prefixHelpText', { - defaultMessage: 'Prefix to be added to extracted keys.', + defaultMessage: 'Prefix to add to extracted keys.', }), }, @@ -136,7 +147,7 @@ const fieldsConfig: FieldsConfig = { helpText: ( {'()'}, angle: <>, @@ -154,7 +165,7 @@ export const Kv: FunctionComponent = () => { <> @@ -166,8 +177,7 @@ export const Kv: FunctionComponent = () => { helpText={i18n.translate( 'xpack.ingestPipelines.pipelineEditor.kvForm.targetFieldHelpText', { - defaultMessage: - 'Field to insert the extracted keys into. Defaults to the root of the document.', + defaultMessage: 'Output field for the extracted fields. Defaults to the document root.', } )} /> diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/lowercase.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/lowercase.tsx index 9db313a05007..0d8170338ea1 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/lowercase.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/lowercase.tsx @@ -6,8 +6,6 @@ import React, { FunctionComponent } from 'react'; import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiCode } from '@elastic/eui'; import { FieldNameField } from './common_fields/field_name_field'; import { TargetField } from './common_fields/target_field'; @@ -23,17 +21,7 @@ export const Lowercase: FunctionComponent = () => { )} /> - {'field'}, - }} - /> - } - /> + diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/pipeline.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/pipeline.tsx index c785cf935833..57843e241135 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/pipeline.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/pipeline.tsx @@ -27,7 +27,7 @@ const fieldsConfig: FieldsConfig = { helpText: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.pipelineForm.pipelineNameFieldHelpText', { - defaultMessage: 'Name of the pipeline to execute.', + defaultMessage: 'Name of the ingest pipeline to run.', } ), validations: [ diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/remove.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/remove.tsx index 3e90ce2b76f7..3ba1cdb0c802 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/remove.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/remove.tsx @@ -29,7 +29,7 @@ const fieldsConfig: FieldsConfig = { defaultMessage: 'Fields', }), helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.removeForm.fieldNameHelpText', { - defaultMessage: 'Fields to be removed.', + defaultMessage: 'Fields to remove.', }), validations: [ { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/rename.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/rename.tsx index 8b796d966458..099e2bd2c80f 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/rename.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/rename.tsx @@ -21,7 +21,7 @@ export const Rename: FunctionComponent = () => { @@ -31,7 +31,7 @@ export const Rename: FunctionComponent = () => { })} helpText={i18n.translate( 'xpack.ingestPipelines.pipelineEditor.renameForm.targetFieldHelpText', - { defaultMessage: 'Name of the new field.' } + { defaultMessage: 'New field name. This field cannot already exist.' } )} validations={[ { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/script.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/script.tsx index ae0bbbb490ae..de28f6676660 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/script.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/script.tsx @@ -32,7 +32,7 @@ const fieldsConfig: FieldsConfig = { helpText: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.scriptForm.storedScriptIDFieldHelpText', { - defaultMessage: 'Stored script reference.', + defaultMessage: 'ID of the stored script to run.', } ), validations: [ @@ -55,7 +55,7 @@ const fieldsConfig: FieldsConfig = { helpText: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.scriptForm.sourceFieldHelpText', { - defaultMessage: 'Script to be executed.', + defaultMessage: 'Inline script to run.', } ), validations: [ @@ -98,7 +98,7 @@ const fieldsConfig: FieldsConfig = { helpText: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.scriptForm.paramsFieldHelpText', { - defaultMessage: 'Script parameters.', + defaultMessage: 'Named parameters passed to the script as variables.', } ), validations: [ @@ -128,7 +128,7 @@ export const Script: FormFieldsComponent = ({ initialFieldValues }) => { setShowId((v) => !v)} diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set.tsx index c282be35e507..04ea0c44c351 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set.tsx @@ -32,13 +32,13 @@ const fieldsConfig: FieldsConfig = { defaultMessage: 'Value', }), helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.setForm.valueFieldHelpText', { - defaultMessage: 'Value to be set for the field', + defaultMessage: 'Value for the field.', }), validations: [ { validator: emptyField( i18n.translate('xpack.ingestPipelines.pipelineEditor.setForm.valueRequiredError', { - defaultMessage: 'A value is required', + defaultMessage: 'A value is required.', }) ), }, @@ -53,9 +53,15 @@ const fieldsConfig: FieldsConfig = { label: i18n.translate('xpack.ingestPipelines.pipelineEditor.setForm.overrideFieldLabel', { defaultMessage: 'Override', }), - helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.setForm.overrideFieldHelpText', { - defaultMessage: 'If disabled, fields containing non-null values will not be updated.', - }), + helpText: ( + {'null'}, + }} + /> + ), }, ignore_empty_value: { type: FIELD_TYPES.TOGGLE, @@ -71,7 +77,8 @@ const fieldsConfig: FieldsConfig = { helpText: ( {'value'}, nullValue: {'null'}, @@ -89,7 +96,7 @@ export const SetProcessor: FunctionComponent = () => { <> diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set_security_user.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set_security_user.tsx index 78128b3d54c7..46bfe8c97ebe 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set_security_user.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/set_security_user.tsx @@ -44,7 +44,7 @@ const fieldsConfig: FieldsConfig = { helpText: ( [{helpTextValues}], }} @@ -60,7 +60,7 @@ export const SetSecurityUser: FunctionComponent = () => { helpText={i18n.translate( 'xpack.ingestPipelines.pipelineEditor.setSecurityUserForm.fieldNameField', { - defaultMessage: 'Field to store the user information', + defaultMessage: 'Output field.', } )} /> diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/sort.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/sort.tsx index cdd0ff888acc..c8c0562011fd 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/sort.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/sort.tsx @@ -24,7 +24,8 @@ const fieldsConfig: FieldsConfig = { defaultMessage: 'Order', }), helpText: i18n.translate('xpack.ingestPipelines.pipelineEditor.sortForm.orderFieldHelpText', { - defaultMessage: 'Sort order to use', + defaultMessage: + 'Sort order. Arrays containing a mix of strings and numbers are sorted lexicographically.', }), }, }; @@ -35,7 +36,7 @@ export const Sort: FunctionComponent = () => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/split.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/split.tsx index b48ce74110b3..fa178aaddd31 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/split.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/manage_processor_form/processors/split.tsx @@ -33,7 +33,7 @@ const fieldsConfig: FieldsConfig = { helpText: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.splitForm.separatorFieldHelpText', { - defaultMessage: 'Regex to match a separator', + defaultMessage: 'Regex pattern used to delimit the field value.', } ), validations: [ @@ -60,7 +60,7 @@ const fieldsConfig: FieldsConfig = { ), helpText: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.splitForm.preserveTrailingFieldHelpText', - { defaultMessage: 'If enabled, preserve any trailing space.' } + { defaultMessage: 'Preserve any trailing whitespace in the split field values.' } ), }, }; @@ -71,7 +71,7 @@ export const Split: FunctionComponent = () => { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/map_processor_type_to_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/map_processor_type_to_form.tsx index 59ec64944a3c..9de371f8d002 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/map_processor_type_to_form.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_processors_editor/components/shared/map_processor_type_to_form.tsx @@ -107,7 +107,7 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { defaultMessage: 'CSV', }), description: i18n.translate('xpack.ingestPipelines.processors.description.csv', { - defaultMessage: 'Extracts fields values from CSV data.', + defaultMessage: 'Extracts field values from CSV data.', }), }, date: { @@ -306,7 +306,10 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { FieldsComponent: Kv, docLinkPath: '/kv-processor.html', label: i18n.translate('xpack.ingestPipelines.processors.label.kv', { - defaultMessage: 'KV', + defaultMessage: 'Key-value (KV)', + }), + description: i18n.translate('xpack.ingestPipelines.processors.description.kv', { + defaultMessage: 'Extracts fields from a string containing key-value pairs.', }), }, lowercase: { @@ -315,6 +318,9 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { label: i18n.translate('xpack.ingestPipelines.processors.label.lowercase', { defaultMessage: 'Lowercase', }), + description: i18n.translate('xpack.ingestPipelines.processors.description.lowercase', { + defaultMessage: 'Converts a string to lowercase.', + }), }, pipeline: { FieldsComponent: Pipeline, @@ -322,6 +328,9 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { label: i18n.translate('xpack.ingestPipelines.processors.label.pipeline', { defaultMessage: 'Pipeline', }), + description: i18n.translate('xpack.ingestPipelines.processors.description.pipeline', { + defaultMessage: 'Runs another ingest node pipeline.', + }), }, remove: { FieldsComponent: Remove, @@ -329,6 +338,9 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { label: i18n.translate('xpack.ingestPipelines.processors.label.remove', { defaultMessage: 'Remove', }), + description: i18n.translate('xpack.ingestPipelines.processors.description.remove', { + defaultMessage: 'Removes one or more fields.', + }), }, rename: { FieldsComponent: Rename, @@ -336,6 +348,9 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { label: i18n.translate('xpack.ingestPipelines.processors.label.rename', { defaultMessage: 'Rename', }), + description: i18n.translate('xpack.ingestPipelines.processors.description.rename', { + defaultMessage: 'Renames an existing field.', + }), }, script: { FieldsComponent: Script, @@ -343,6 +358,9 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { label: i18n.translate('xpack.ingestPipelines.processors.label.script', { defaultMessage: 'Script', }), + description: i18n.translate('xpack.ingestPipelines.processors.description.script', { + defaultMessage: 'Runs a script on incoming documents.', + }), }, set: { FieldsComponent: SetProcessor, @@ -350,6 +368,9 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { label: i18n.translate('xpack.ingestPipelines.processors.label.set', { defaultMessage: 'Set', }), + description: i18n.translate('xpack.ingestPipelines.processors.description.set', { + defaultMessage: 'Sets the value of a field.', + }), }, set_security_user: { FieldsComponent: SetSecurityUser, @@ -357,12 +378,9 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { label: i18n.translate('xpack.ingestPipelines.processors.label.setSecurityUser', { defaultMessage: 'Set security user', }), - }, - split: { - FieldsComponent: Split, - docLinkPath: '/split-processor.html', - label: i18n.translate('xpack.ingestPipelines.processors.label.split', { - defaultMessage: 'Split', + description: i18n.translate('xpack.ingestPipelines.processors.description.setSecurityUser', { + defaultMessage: + 'Adds details about the current user, such user name and email address, to incoming documents. Requires an authenticated user for the indexing request.', }), }, sort: { @@ -371,6 +389,19 @@ export const mapProcessorTypeToDescriptor: MapProcessorTypeToDescriptor = { label: i18n.translate('xpack.ingestPipelines.processors.label.sort', { defaultMessage: 'Sort', }), + description: i18n.translate('xpack.ingestPipelines.processors.description.sort', { + defaultMessage: "Sorts a field's array elements.", + }), + }, + split: { + FieldsComponent: Split, + docLinkPath: '/split-processor.html', + label: i18n.translate('xpack.ingestPipelines.processors.label.split', { + defaultMessage: 'Split', + }), + description: i18n.translate('xpack.ingestPipelines.processors.description.split', { + defaultMessage: 'Splits a field value into an array.', + }), }, trim: { FieldsComponent: undefined, // TODO: Implement diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/main.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/main.tsx index ccb50376dddb..88148f1bc574 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/main.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/main.tsx @@ -51,7 +51,7 @@ export const PipelinesList: React.FunctionComponent = ({ const [pipelinesToDelete, setPipelinesToDelete] = useState([]); - const { data, isLoading, error, sendRequest } = services.api.useLoadPipelines(); + const { data, isLoading, error, resendRequest } = services.api.useLoadPipelines(); // Track component loaded useEffect(() => { @@ -98,7 +98,7 @@ export const PipelinesList: React.FunctionComponent = ({ } else if (data?.length) { content = ( = ({ defaultMessage="Unable to load pipelines. {reloadLink}" values={{ reloadLink: ( - + = ({ callback={(deleteResponse) => { if (deleteResponse?.hasDeletedPipelines) { // reload pipelines list - sendRequest(); + resendRequest(); setSelectedPipeline(undefined); goHome(); } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.tsx index 198be7085f5f..e5d63f1f92e1 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/bucket_nesting_editor.tsx @@ -80,7 +80,8 @@ export function BucketNestingEditor({ values: { field: fieldName }, }) : i18n.translate('xpack.lens.indexPattern.groupingOverallDateHistogram', { - defaultMessage: 'Dates overall', + defaultMessage: 'Top values for each {field}', + values: { field: fieldName }, }) } checked={!prevColumn} @@ -96,7 +97,7 @@ export function BucketNestingEditor({ values: { target: target.fieldName }, }) : i18n.translate('xpack.lens.indexPattern.groupingSecondDateHistogram', { - defaultMessage: 'Dates for each {target}', + defaultMessage: 'Overall top {target}', values: { target: target.fieldName }, }) } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx index a0cc5ec35213..cf15c2984405 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/field_item.tsx @@ -117,14 +117,7 @@ export const InnerFieldItem = function InnerFieldItem(props: FieldItemProps) { ); function fetchData() { - if ( - state.isLoading || - (field.type !== 'number' && - field.type !== 'string' && - field.type !== 'date' && - field.type !== 'boolean' && - field.type !== 'ip') - ) { + if (state.isLoading) { return; } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts index 660be9514a92..19213d4afc9b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/loader.test.ts @@ -93,6 +93,16 @@ const indexPattern1 = ({ searchable: true, esTypes: ['keyword'], }, + { + name: 'scripted', + displayName: 'Scripted', + type: 'string', + searchable: true, + aggregatable: true, + scripted: true, + lang: 'painless', + script: '1234', + }, documentField, ], } as unknown) as IndexPattern; @@ -156,12 +166,13 @@ const indexPattern2 = ({ aggregatable: true, searchable: true, scripted: true, + lang: 'painless', + script: '1234', aggregationRestrictions: { terms: { agg: 'terms', }, }, - esTypes: ['keyword'], }, documentField, ], diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts b/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts index 585a1281cbf5..0ab658b96133 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/loader.ts @@ -55,15 +55,27 @@ export async function loadIndexPatterns({ !indexPatternsUtils.isNestedField(field) && (!!field.aggregatable || !!field.scripted) ) .map( - (field): IndexPatternField => ({ - name: field.name, - displayName: field.displayName, - type: field.type, - aggregatable: field.aggregatable, - searchable: field.searchable, - scripted: field.scripted, - esTypes: field.esTypes, - }) + (field): IndexPatternField => { + // Convert the getters on the index pattern service into plain JSON + const base = { + name: field.name, + displayName: field.displayName, + type: field.type, + aggregatable: field.aggregatable, + searchable: field.searchable, + esTypes: field.esTypes, + scripted: field.scripted, + }; + + // Simplifies tests by hiding optional properties instead of undefined + return base.scripted + ? { + ...base, + lang: field.lang, + script: field.script, + } + : base; + } ) .concat(documentField); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts b/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts index 31e6240993d3..21ed23321cf5 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/mocks.ts @@ -64,6 +64,16 @@ export const createMockedIndexPattern = (): IndexPattern => ({ searchable: true, esTypes: ['keyword'], }, + { + name: 'scripted', + displayName: 'Scripted', + type: 'string', + searchable: true, + aggregatable: true, + scripted: true, + lang: 'painless', + script: '1234', + }, ], }); @@ -95,6 +105,8 @@ export const createMockedRestrictedIndexPattern = () => ({ searchable: true, scripted: true, esTypes: ['keyword'], + lang: 'painless', + script: '1234', }, ], typeMeta: { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/types.ts b/x-pack/plugins/lens/public/indexpattern_datasource/types.ts index c101f1354b70..21ca41234fdf 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/types.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/types.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { IFieldType } from 'src/plugins/data/common'; import { IndexPatternColumn } from './operations'; import { IndexPatternAggRestrictions } from '../../../../../src/plugins/data/public'; @@ -22,16 +23,10 @@ export interface IndexPattern { hasRestrictions: boolean; } -export interface IndexPatternField { - name: string; +export type IndexPatternField = IFieldType & { displayName: string; - type: string; - esTypes?: string[]; - aggregatable: boolean; - scripted?: boolean; - searchable: boolean; aggregationRestrictions?: Partial; -} +}; export interface IndexPatternLayer { columnOrder: string[]; diff --git a/x-pack/plugins/lens/server/routes/field_stats.ts b/x-pack/plugins/lens/server/routes/field_stats.ts index 20d3e2b4164c..a7368a12f0e2 100644 --- a/x-pack/plugins/lens/server/routes/field_stats.ts +++ b/x-pack/plugins/lens/server/routes/field_stats.ts @@ -8,6 +8,7 @@ import Boom from 'boom'; import DateMath from '@elastic/datemath'; import { schema } from '@kbn/config-schema'; import { CoreSetup } from 'src/core/server'; +import { IFieldType } from 'src/plugins/data/common'; import { ESSearchResponse } from '../../../apm/typings/elasticsearch'; import { FieldStatsResponse, BASE_API_URL } from '../../common'; @@ -33,6 +34,9 @@ export async function initFieldsRoute(setup: CoreSetup) { name: schema.string(), type: schema.string(), esTypes: schema.maybe(schema.arrayOf(schema.string())), + scripted: schema.maybe(schema.boolean()), + lang: schema.maybe(schema.string()), + script: schema.maybe(schema.string()), }, { unknowns: 'allow' } ), @@ -83,21 +87,15 @@ export async function initFieldsRoute(setup: CoreSetup) { return res.ok({ body: await getNumberHistogram(search, field), }); - } else if (field.type === 'string') { - return res.ok({ - body: await getStringSamples(search, field), - }); } else if (field.type === 'date') { return res.ok({ body: await getDateHistogram(search, field, { fromDate, toDate }), }); - } else if (field.type === 'boolean') { - return res.ok({ - body: await getStringSamples(search, field), - }); } - return res.ok({}); + return res.ok({ + body: await getStringSamples(search, field), + }); } catch (e) { if (e.status === 404) { return res.notFound(); @@ -119,8 +117,10 @@ export async function initFieldsRoute(setup: CoreSetup) { export async function getNumberHistogram( aggSearchWithBody: (body: unknown) => Promise, - field: { name: string; type: string; esTypes?: string[] } + field: IFieldType ): Promise { + const fieldRef = getFieldRef(field); + const searchBody = { sample: { sampler: { shard_size: SHARD_SIZE }, @@ -131,9 +131,9 @@ export async function getNumberHistogram( max_value: { max: { field: field.name }, }, - sample_count: { value_count: { field: field.name } }, + sample_count: { value_count: { ...fieldRef } }, top_values: { - terms: { field: field.name, size: 10 }, + terms: { ...fieldRef, size: 10 }, }, }, }, @@ -206,15 +206,20 @@ export async function getNumberHistogram( export async function getStringSamples( aggSearchWithBody: (body: unknown) => unknown, - field: { name: string; type: string } + field: IFieldType ): Promise { + const fieldRef = getFieldRef(field); + const topValuesBody = { sample: { sampler: { shard_size: SHARD_SIZE }, aggs: { - sample_count: { value_count: { field: field.name } }, + sample_count: { value_count: { ...fieldRef } }, top_values: { - terms: { field: field.name, size: 10 }, + terms: { + ...fieldRef, + size: 10, + }, }, }, }, @@ -241,7 +246,7 @@ export async function getStringSamples( // This one is not sampled so that it returns the full date range export async function getDateHistogram( aggSearchWithBody: (body: unknown) => unknown, - field: { name: string; type: string }, + field: IFieldType, range: { fromDate: string; toDate: string } ): Promise { const fromDate = DateMath.parse(range.fromDate); @@ -265,7 +270,7 @@ export async function getDateHistogram( const fixedInterval = `${interval}ms`; const histogramBody = { - histo: { date_histogram: { field: field.name, fixed_interval: fixedInterval } }, + histo: { date_histogram: { ...getFieldRef(field), fixed_interval: fixedInterval } }, }; const results = (await aggSearchWithBody(histogramBody)) as ESSearchResponse< unknown, @@ -283,3 +288,14 @@ export async function getDateHistogram( }, }; } + +function getFieldRef(field: IFieldType) { + return field.scripted + ? { + script: { + lang: field.lang as string, + source: field.script as string, + }, + } + : { field: field.name }; +} diff --git a/x-pack/plugins/maps/public/classes/joins/inner_join.js b/x-pack/plugins/maps/public/classes/joins/inner_join.js index 76afe2430b81..75bf59d9d640 100644 --- a/x-pack/plugins/maps/public/classes/joins/inner_join.js +++ b/x-pack/plugins/maps/public/classes/joins/inner_join.js @@ -94,8 +94,8 @@ export class InnerJoin { return this._descriptor; } - async filterAndFormatPropertiesForTooltip(properties) { - return await this._rightSource.filterAndFormatPropertiesToHtml(properties); + async getTooltipProperties(properties) { + return await this._rightSource.getTooltipProperties(properties); } getIndexPatternIds() { diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.js b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.js index c49d0044e6ad..27c344b713a6 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.js +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.js @@ -949,13 +949,11 @@ export class VectorLayer extends AbstractLayer { async getPropertiesForTooltip(properties) { const vectorSource = this.getSource(); - let allProperties = await vectorSource.filterAndFormatPropertiesToHtml(properties); + let allProperties = await vectorSource.getTooltipProperties(properties); this._addJoinsToSourceTooltips(allProperties); for (let i = 0; i < this.getJoins().length; i++) { - const propsFromJoin = await this.getJoins()[i].filterAndFormatPropertiesForTooltip( - properties - ); + const propsFromJoin = await this.getJoins()[i].getTooltipProperties(properties); allProperties = [...allProperties, ...propsFromJoin]; } return allProperties; diff --git a/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.test.tsx b/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.test.tsx index c5d6ced76b5c..674ee832daab 100644 --- a/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.test.tsx +++ b/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.test.tsx @@ -17,10 +17,10 @@ function makeEMSFileSource(tooltipProperties: string[]) { } describe('EMS file source', () => { - describe('filterAndFormatPropertiesToHtml', () => { + describe('getTooltipProperties', () => { it('should create tooltip-properties with human readable label', async () => { const mockEMSFileSource = makeEMSFileSource(['iso2']); - const out = await mockEMSFileSource.filterAndFormatPropertiesToHtml({ + const out = await mockEMSFileSource.getTooltipProperties({ iso2: 'US', }); @@ -33,7 +33,7 @@ describe('EMS file source', () => { it('should order tooltip-properties', async () => { const tooltipProperties = ['iso3', 'iso2', 'name']; const mockEMSFileSource = makeEMSFileSource(tooltipProperties); - const out = await mockEMSFileSource.filterAndFormatPropertiesToHtml({ + const out = await mockEMSFileSource.getTooltipProperties({ name: 'United States', iso3: 'USA', iso2: 'US', diff --git a/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.tsx b/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.tsx index f55a7434d121..5f73a9e23431 100644 --- a/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/ems_file_source/ems_file_source.tsx @@ -23,7 +23,6 @@ import { ITooltipProperty } from '../../tooltips/tooltip_property'; export interface IEmsFileSource extends IVectorSource { getEmsFieldLabel(emsFieldName: string): Promise; - createField({ fieldName }: { fieldName: string }): IField; } export const sourceTitle = i18n.translate('xpack.maps.source.emsFileTitle', { @@ -168,7 +167,7 @@ export class EMSFileSource extends AbstractVectorSource implements IEmsFileSourc return this._tooltipFields.length > 0; } - async filterAndFormatPropertiesToHtml(properties: unknown): Promise { + async getTooltipProperties(properties: unknown): Promise { const promises = this._tooltipFields.map((field) => { // @ts-ignore const value = properties[field.getName()]; diff --git a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.d.ts b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.d.ts deleted file mode 100644 index eb50cd7528c8..000000000000 --- a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { IESSource } from '../es_source'; -import { AbstractESSource } from '../es_source'; -import { AGG_TYPE } from '../../../../common/constants'; -import { IESAggField } from '../../fields/es_agg_field'; -import { AbstractESAggSourceDescriptor } from '../../../../common/descriptor_types'; - -export interface IESAggSource extends IESSource { - getAggKey(aggType: AGG_TYPE, fieldName: string): string; - getAggLabel(aggType: AGG_TYPE, fieldName: string): string; - getMetricFields(): IESAggField[]; - hasMatchingMetricField(fieldName: string): boolean; - getMetricFieldForName(fieldName: string): IESAggField | null; -} - -export class AbstractESAggSource extends AbstractESSource implements IESAggSource { - constructor(sourceDescriptor: AbstractESAggSourceDescriptor, inspectorAdapters: object); - - getAggKey(aggType: AGG_TYPE, fieldName: string): string; - getAggLabel(aggType: AGG_TYPE, fieldName: string): string; - getMetricFields(): IESAggField[]; - hasMatchingMetricField(fieldName: string): boolean; - getMetricFieldForName(fieldName: string): IESAggField | null; -} diff --git a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.js b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts similarity index 56% rename from x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.js rename to x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts index e20c509ccd4a..a9c886617d3a 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.js +++ b/x-pack/plugins/maps/public/classes/sources/es_agg_source/es_agg_source.ts @@ -5,19 +5,38 @@ */ import { i18n } from '@kbn/i18n'; +import { Adapters } from 'src/plugins/inspector/public'; +import { GeoJsonProperties } from 'geojson'; +import { IESSource } from '../es_source'; import { AbstractESSource } from '../es_source'; import { esAggFieldsFactory } from '../../fields/es_agg_field'; import { AGG_TYPE, COUNT_PROP_LABEL, FIELD_ORIGIN } from '../../../../common/constants'; +import { IESAggField } from '../../fields/es_agg_field'; import { getSourceAggKey } from '../../../../common/get_agg_key'; +import { AbstractESAggSourceDescriptor, AggDescriptor } from '../../../../common/descriptor_types'; +import { IndexPattern } from '../../../../../../../src/plugins/data/public'; +import { IField } from '../../fields/field'; +import { ITooltipProperty } from '../../tooltips/tooltip_property'; export const DEFAULT_METRIC = { type: AGG_TYPE.COUNT }; +export interface IESAggSource extends IESSource { + getAggKey(aggType: AGG_TYPE, fieldName: string): string; + getAggLabel(aggType: AGG_TYPE, fieldName: string): string; + getMetricFields(): IESAggField[]; + hasMatchingMetricField(fieldName: string): boolean; + getMetricFieldForName(fieldName: string): IESAggField | null; + getValueAggsDsl(indexPattern: IndexPattern): { [key: string]: unknown }; +} + export class AbstractESAggSource extends AbstractESSource { - constructor(descriptor, inspectorAdapters) { + private readonly _metricFields: IESAggField[]; + + constructor(descriptor: AbstractESAggSourceDescriptor, inspectorAdapters: Adapters) { super(descriptor, inspectorAdapters); this._metricFields = []; - if (this._descriptor.metrics) { - this._descriptor.metrics.forEach((aggDescriptor) => { + if (descriptor.metrics) { + descriptor.metrics.forEach((aggDescriptor: AggDescriptor) => { this._metricFields.push( ...esAggFieldsFactory(aggDescriptor, this, this.getOriginForField()) ); @@ -25,30 +44,31 @@ export class AbstractESAggSource extends AbstractESSource { } } - getFieldByName(name) { - return this.getMetricFieldForName(name); + getFieldByName(fieldName: string) { + return this.getMetricFieldForName(fieldName); } - createField() { + createField({ fieldName }: { fieldName: string }): IField { throw new Error('Cannot create a new field from just a fieldname for an es_agg_source.'); } - hasMatchingMetricField(fieldName) { + hasMatchingMetricField(fieldName: string): boolean { const matchingField = this.getMetricFieldForName(fieldName); return !!matchingField; } - getMetricFieldForName(fieldName) { - return this.getMetricFields().find((metricField) => { + getMetricFieldForName(fieldName: string): IESAggField | null { + const targetMetricField = this.getMetricFields().find((metricField: IESAggField) => { return metricField.getName() === fieldName; }); + return targetMetricField ? targetMetricField : null; } getOriginForField() { return FIELD_ORIGIN.SOURCE; } - getMetricFields() { + getMetricFields(): IESAggField[] { const metrics = this._metricFields.filter((esAggField) => esAggField.isValid()); // Handle case where metrics is empty because older saved object state is empty array or there are no valid aggs. return metrics.length === 0 @@ -56,14 +76,14 @@ export class AbstractESAggSource extends AbstractESSource { : metrics; } - getAggKey(aggType, fieldName) { + getAggKey(aggType: AGG_TYPE, fieldName: string): string { return getSourceAggKey({ aggType, aggFieldName: fieldName, }); } - getAggLabel(aggType, fieldName) { + getAggLabel(aggType: AGG_TYPE, fieldName: string): string { switch (aggType) { case AGG_TYPE.COUNT: return COUNT_PROP_LABEL; @@ -81,8 +101,8 @@ export class AbstractESAggSource extends AbstractESSource { return this.getMetricFields(); } - getValueAggsDsl(indexPattern) { - const valueAggsDsl = {}; + getValueAggsDsl(indexPattern: IndexPattern) { + const valueAggsDsl: { [key: string]: unknown } = {}; this.getMetricFields().forEach((esAggMetric) => { const aggDsl = esAggMetric.getValueAggDsl(indexPattern); if (aggDsl) { @@ -92,9 +112,9 @@ export class AbstractESAggSource extends AbstractESSource { return valueAggsDsl; } - async filterAndFormatPropertiesToHtmlForMetricFields(properties) { - const metricFields = this.getMetricFields(); - const tooltipPropertiesPromises = []; + async getTooltipProperties(properties: GeoJsonProperties) { + const metricFields = await this.getFields(); + const promises: Array> = []; metricFields.forEach((metricField) => { let value; for (const key in properties) { @@ -105,9 +125,9 @@ export class AbstractESAggSource extends AbstractESSource { } const tooltipPromise = metricField.createTooltipProperty(value); - tooltipPropertiesPromises.push(tooltipPromise); + promises.push(tooltipPromise); }); - return await Promise.all(tooltipPropertiesPromises); + return await Promise.all(promises); } } diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.d.ts b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.d.ts index 51ee15e7ea5a..2ce4353fca13 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.d.ts +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.d.ts @@ -7,6 +7,7 @@ import { AbstractESAggSource } from '../es_agg_source'; import { ESGeoGridSourceDescriptor } from '../../../../common/descriptor_types'; import { GRID_RESOLUTION } from '../../../../common/constants'; +import { IField } from '../../fields/field'; export class ESGeoGridSource extends AbstractESAggSource { static createDescriptor({ @@ -21,4 +22,5 @@ export class ESGeoGridSource extends AbstractESAggSource { getFieldNames(): string[]; getGridResolution(): GRID_RESOLUTION; getGeoGridPrecision(zoom: number): number; + createField({ fieldName }: { fieldName: string }): IField; } diff --git a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.js b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.js index a6322ff3ba78..aa167cb57767 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.js +++ b/x-pack/plugins/maps/public/classes/sources/es_geo_grid_source/es_geo_grid_source.js @@ -321,10 +321,6 @@ export class ESGeoGridSource extends AbstractESAggSource { return true; } - async filterAndFormatPropertiesToHtml(properties) { - return await this.filterAndFormatPropertiesToHtmlForMetricFields(properties); - } - async getSupportedShapeTypes() { if (this._descriptor.requestType === RENDER_AS.GRID) { return [VECTOR_SHAPE_TYPE.POLYGON]; diff --git a/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.js b/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.js index 92b0c717f672..9ec54335d4e7 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.js +++ b/x-pack/plugins/maps/public/classes/sources/es_pew_pew_source/es_pew_pew_source.js @@ -223,10 +223,6 @@ export class ESPewPewSource extends AbstractESAggSource { canFormatFeatureProperties() { return true; } - - async filterAndFormatPropertiesToHtml(properties) { - return await this.filterAndFormatPropertiesToHtmlForMetricFields(properties); - } } registerSource({ diff --git a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.js b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.js index 7ac2738eaeb5..df83bd1cf5e6 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.js +++ b/x-pack/plugins/maps/public/classes/sources/es_search_source/es_search_source.js @@ -438,7 +438,7 @@ export class ESSearchSource extends AbstractESSource { return properties; } - async filterAndFormatPropertiesToHtml(properties) { + async getTooltipProperties(properties) { const indexPattern = await this.getIndexPattern(); const propertyValues = await this._loadTooltipProperties( properties._id, diff --git a/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.js b/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.js index 8cc8dd5c4a08..b4ad256c1598 100644 --- a/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.js +++ b/x-pack/plugins/maps/public/classes/sources/es_term_source/es_term_source.js @@ -129,10 +129,6 @@ export class ESTermSource extends AbstractESAggSource { return `es_table ${this.getIndexPatternId()}`; } - async filterAndFormatPropertiesToHtml(properties) { - return await this.filterAndFormatPropertiesToHtmlForMetricFields(properties); - } - getFieldNames() { return this.getMetricFields().map((esAggMetricField) => esAggMetricField.getName()); } diff --git a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.test.tsx b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.test.tsx index 4e9e1e9cd768..48f7b30261f3 100644 --- a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.test.tsx +++ b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.test.tsx @@ -45,7 +45,7 @@ describe('canFormatFeatureProperties', () => { }); }); -describe('filterAndFormatPropertiesToHtml', () => { +describe('getTooltipProperties', () => { const descriptorWithFields = { ...descriptor, fields: [ @@ -67,7 +67,7 @@ describe('filterAndFormatPropertiesToHtml', () => { it('should get tooltipproperties', async () => { const source = new MVTSingleLayerVectorSource(descriptorWithFields); - const tooltipProperties = await source.filterAndFormatPropertiesToHtml({ + const tooltipProperties = await source.getTooltipProperties({ foo: 'bar', fooz: 123, }); diff --git a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx index 52dc89a6bba5..3e515613b3fd 100644 --- a/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/mvt_single_layer_vector_source/mvt_single_layer_vector_source.tsx @@ -192,7 +192,7 @@ export class MVTSingleLayerVectorSource return false; } - async filterAndFormatPropertiesToHtml( + async getTooltipProperties( properties: GeoJsonProperties, featureId?: string | number ): Promise { diff --git a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.d.ts b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.d.ts index fd9c17927544..a481e273bc33 100644 --- a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.d.ts +++ b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.d.ts @@ -36,7 +36,7 @@ export type BoundsFilters = { }; export interface IVectorSource extends ISource { - filterAndFormatPropertiesToHtml(properties: GeoJsonProperties): Promise; + getTooltipProperties(properties: GeoJsonProperties): Promise; getBoundsForFilters( boundsFilters: BoundsFilters, registerCancelCallback: (requestToken: symbol, callback: () => void) => void @@ -58,7 +58,7 @@ export interface IVectorSource extends ISource { } export class AbstractVectorSource extends AbstractSource implements IVectorSource { - filterAndFormatPropertiesToHtml(properties: GeoJsonProperties): Promise; + getTooltipProperties(properties: GeoJsonProperties): Promise; getBoundsForFilters( boundsFilters: BoundsFilters, registerCancelCallback: (requestToken: symbol, callback: () => void) => void diff --git a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.js b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.js index 98ed89a6ff0a..9569b8626aab 100644 --- a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.js +++ b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.js @@ -106,7 +106,7 @@ export class AbstractVectorSource extends AbstractSource { } // Allow source to filter and format feature properties before displaying to user - async filterAndFormatPropertiesToHtml(properties) { + async getTooltipProperties(properties) { const tooltipProperties = []; for (const key in properties) { if (key.startsWith('__kbn')) { diff --git a/x-pack/plugins/maps/public/components/_index.scss b/x-pack/plugins/maps/public/components/_index.scss index 76ce9f1bc79e..726573ce4307 100644 --- a/x-pack/plugins/maps/public/components/_index.scss +++ b/x-pack/plugins/maps/public/components/_index.scss @@ -1,4 +1,4 @@ @import 'action_select'; -@import 'metric_editors'; +@import 'metrics_editor/metric_editors'; @import './geometry_filter'; @import 'tooltip_selector/tooltip_selector'; diff --git a/x-pack/plugins/maps/public/components/__snapshots__/metrics_editor.test.js.snap b/x-pack/plugins/maps/public/components/metrics_editor/__snapshots__/metrics_editor.test.tsx.snap similarity index 92% rename from x-pack/plugins/maps/public/components/__snapshots__/metrics_editor.test.js.snap rename to x-pack/plugins/maps/public/components/metrics_editor/__snapshots__/metrics_editor.test.tsx.snap index 0d4f1f99e464..bd58ded41e7f 100644 --- a/x-pack/plugins/maps/public/components/__snapshots__/metrics_editor.test.js.snap +++ b/x-pack/plugins/maps/public/components/metrics_editor/__snapshots__/metrics_editor.test.tsx.snap @@ -16,8 +16,9 @@ exports[`should add default count metric when metrics is empty array 1`] = ` "type": "count", } } - metricsFilter={[Function]} onChange={[Function]} + onRemove={[Function]} + showRemoveButton={false} /> @@ -59,8 +60,9 @@ exports[`should render metrics editor 1`] = ` "type": "sum", } } - metricsFilter={[Function]} onChange={[Function]} + onRemove={[Function]} + showRemoveButton={false} /> diff --git a/x-pack/plugins/maps/public/components/_metric_editors.scss b/x-pack/plugins/maps/public/components/metrics_editor/_metric_editors.scss similarity index 100% rename from x-pack/plugins/maps/public/components/_metric_editors.scss rename to x-pack/plugins/maps/public/components/metrics_editor/_metric_editors.scss diff --git a/x-pack/plugins/maps/public/components/metrics_editor/index.ts b/x-pack/plugins/maps/public/components/metrics_editor/index.ts new file mode 100644 index 000000000000..3c105c2d798f --- /dev/null +++ b/x-pack/plugins/maps/public/components/metrics_editor/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { MetricsEditor } from './metrics_editor'; diff --git a/x-pack/plugins/maps/public/components/metric_editor.js b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx similarity index 59% rename from x-pack/plugins/maps/public/components/metric_editor.js rename to x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx index 96b52d84653b..543d144efdcc 100644 --- a/x-pack/plugins/maps/public/components/metric_editor.js +++ b/x-pack/plugins/maps/public/components/metrics_editor/metric_editor.tsx @@ -4,18 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Fragment } from 'react'; -import PropTypes from 'prop-types'; +import React, { ChangeEvent, Fragment } from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiFieldText, EuiFormRow } from '@elastic/eui'; +import { EuiButtonEmpty, EuiComboBoxOptionOption, EuiFieldText, EuiFormRow } from '@elastic/eui'; -import { MetricSelect, METRIC_AGGREGATION_VALUES } from './metric_select'; -import { SingleFieldSelect } from './single_field_select'; -import { AGG_TYPE } from '../../common/constants'; -import { getTermsFields } from '../index_pattern_util'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { MetricSelect } from './metric_select'; +import { SingleFieldSelect } from '../single_field_select'; +import { AggDescriptor } from '../../../common/descriptor_types'; +import { AGG_TYPE } from '../../../common/constants'; +import { getTermsFields } from '../../index_pattern_util'; +import { IFieldType } from '../../../../../../src/plugins/data/public'; -function filterFieldsForAgg(fields, aggType) { +function filterFieldsForAgg(fields: IFieldType[], aggType: AGG_TYPE) { if (!fields) { return []; } @@ -34,8 +36,27 @@ function filterFieldsForAgg(fields, aggType) { }); } -export function MetricEditor({ fields, metricsFilter, metric, onChange, removeButton }) { - const onAggChange = (metricAggregationType) => { +interface Props { + metric: AggDescriptor; + fields: IFieldType[]; + onChange: (metric: AggDescriptor) => void; + onRemove: () => void; + metricsFilter?: (metricOption: EuiComboBoxOptionOption) => boolean; + showRemoveButton: boolean; +} + +export function MetricEditor({ + fields, + metricsFilter, + metric, + onChange, + showRemoveButton, + onRemove, +}: Props) { + const onAggChange = (metricAggregationType?: AGG_TYPE) => { + if (!metricAggregationType) { + return; + } const newMetricProps = { ...metric, type: metricAggregationType, @@ -54,13 +75,16 @@ export function MetricEditor({ fields, metricsFilter, metric, onChange, removeBu onChange(newMetricProps); }; - const onFieldChange = (fieldName) => { + const onFieldChange = (fieldName?: string) => { + if (!fieldName) { + return; + } onChange({ ...metric, field: fieldName, }); }; - const onLabelChange = (e) => { + const onLabelChange = (e: ChangeEvent) => { onChange({ ...metric, label: e.target.value, @@ -80,7 +104,7 @@ export function MetricEditor({ fields, metricsFilter, metric, onChange, removeBu placeholder={i18n.translate('xpack.maps.metricsEditor.selectFieldPlaceholder', { defaultMessage: 'Select field', })} - value={metric.field} + value={metric.field ? metric.field : null} onChange={onFieldChange} fields={filterFieldsForAgg(fields, metric.type)} isClearable={false} @@ -108,6 +132,28 @@ export function MetricEditor({ fields, metricsFilter, metric, onChange, removeBu ); } + let removeButton; + if (showRemoveButton) { + removeButton = ( +
+ + + +
+ ); + } + return ( ); } - -MetricEditor.propTypes = { - metric: PropTypes.shape({ - type: PropTypes.oneOf(METRIC_AGGREGATION_VALUES), - field: PropTypes.string, - label: PropTypes.string, - }), - fields: PropTypes.array, - onChange: PropTypes.func.isRequired, - metricsFilter: PropTypes.func, -}; diff --git a/x-pack/plugins/maps/public/components/metric_select.js b/x-pack/plugins/maps/public/components/metrics_editor/metric_select.tsx similarity index 80% rename from x-pack/plugins/maps/public/components/metric_select.js rename to x-pack/plugins/maps/public/components/metrics_editor/metric_select.tsx index 2ebfcf99dece..197c5466fe0f 100644 --- a/x-pack/plugins/maps/public/components/metric_select.js +++ b/x-pack/plugins/maps/public/components/metrics_editor/metric_select.tsx @@ -5,10 +5,9 @@ */ import React from 'react'; -import PropTypes from 'prop-types'; import { i18n } from '@kbn/i18n'; -import { EuiComboBox } from '@elastic/eui'; -import { AGG_TYPE } from '../../common/constants'; +import { EuiComboBox, EuiComboBoxOptionOption, EuiComboBoxProps } from '@elastic/eui'; +import { AGG_TYPE } from '../../../common/constants'; const AGG_OPTIONS = [ { @@ -55,17 +54,19 @@ const AGG_OPTIONS = [ }, ]; -export const METRIC_AGGREGATION_VALUES = AGG_OPTIONS.map(({ value }) => { - return value; -}); +type Props = Omit, 'onChange'> & { + value: AGG_TYPE; + onChange: (aggType: AGG_TYPE) => void; + metricsFilter?: (metricOption: EuiComboBoxOptionOption) => boolean; +}; -export function MetricSelect({ value, onChange, metricsFilter, ...rest }) { - function onAggChange(selectedOptions) { +export function MetricSelect({ value, onChange, metricsFilter, ...rest }: Props) { + function onAggChange(selectedOptions: Array>) { if (selectedOptions.length === 0) { return; } - const aggType = selectedOptions[0].value; + const aggType = selectedOptions[0].value!; onChange(aggType); } @@ -87,9 +88,3 @@ export function MetricSelect({ value, onChange, metricsFilter, ...rest }) { /> ); } - -MetricSelect.propTypes = { - metricsFilter: PropTypes.func, - value: PropTypes.oneOf(METRIC_AGGREGATION_VALUES), - onChange: PropTypes.func.isRequired, -}; diff --git a/x-pack/plugins/maps/public/components/metrics_editor.test.js b/x-pack/plugins/maps/public/components/metrics_editor/metrics_editor.test.tsx similarity index 84% rename from x-pack/plugins/maps/public/components/metrics_editor.test.js rename to x-pack/plugins/maps/public/components/metrics_editor/metrics_editor.test.tsx index bcbeef29875e..7ce7fbce2b06 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor.test.js +++ b/x-pack/plugins/maps/public/components/metrics_editor/metrics_editor.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import { MetricsEditor } from './metrics_editor'; -import { AGG_TYPE } from '../../common/constants'; +import { AGG_TYPE } from '../../../common/constants'; const defaultProps = { metrics: [ @@ -19,15 +19,14 @@ const defaultProps = { fields: [], onChange: () => {}, allowMultipleMetrics: true, - metricsFilter: () => {}, }; -test('should render metrics editor', async () => { +test('should render metrics editor', () => { const component = shallow(); expect(component).toMatchSnapshot(); }); -test('should add default count metric when metrics is empty array', async () => { +test('should add default count metric when metrics is empty array', () => { const component = shallow(); expect(component).toMatchSnapshot(); }); diff --git a/x-pack/plugins/maps/public/components/metrics_editor.js b/x-pack/plugins/maps/public/components/metrics_editor/metrics_editor.tsx similarity index 54% rename from x-pack/plugins/maps/public/components/metrics_editor.js rename to x-pack/plugins/maps/public/components/metrics_editor/metrics_editor.tsx index 7d4d7bf3ec7a..dae1f5146928 100644 --- a/x-pack/plugins/maps/public/components/metrics_editor.js +++ b/x-pack/plugins/maps/public/components/metrics_editor/metrics_editor.tsx @@ -5,48 +5,42 @@ */ import React, { Fragment } from 'react'; -import PropTypes from 'prop-types'; -import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { EuiButtonEmpty, EuiSpacer, EuiTextAlign } from '@elastic/eui'; +import { EuiButtonEmpty, EuiComboBoxOptionOption, EuiSpacer, EuiTextAlign } from '@elastic/eui'; import { MetricEditor } from './metric_editor'; -import { DEFAULT_METRIC } from '../classes/sources/es_agg_source'; +import { DEFAULT_METRIC } from '../../classes/sources/es_agg_source'; +import { IFieldType } from '../../../../../../src/plugins/data/public'; +import { AggDescriptor } from '../../../common/descriptor_types'; +import { AGG_TYPE } from '../../../common/constants'; -export function MetricsEditor({ fields, metrics, onChange, allowMultipleMetrics, metricsFilter }) { +interface Props { + allowMultipleMetrics: boolean; + metrics: AggDescriptor[]; + fields: IFieldType[]; + onChange: (metrics: AggDescriptor[]) => void; + metricsFilter?: (metricOption: EuiComboBoxOptionOption) => boolean; +} + +export function MetricsEditor({ + fields, + metrics = [DEFAULT_METRIC], + onChange, + allowMultipleMetrics = true, + metricsFilter, +}: Props) { function renderMetrics() { // There was a bug in 7.8 that initialized metrics to []. // This check is needed to handle any saved objects created before the bug was patched. const nonEmptyMetrics = metrics.length === 0 ? [DEFAULT_METRIC] : metrics; return nonEmptyMetrics.map((metric, index) => { - const onMetricChange = (metric) => { - onChange([...metrics.slice(0, index), metric, ...metrics.slice(index + 1)]); + const onMetricChange = (updatedMetric: AggDescriptor) => { + onChange([...metrics.slice(0, index), updatedMetric, ...metrics.slice(index + 1)]); }; const onRemove = () => { onChange([...metrics.slice(0, index), ...metrics.slice(index + 1)]); }; - let removeButton; - if (index > 0) { - removeButton = ( -
- - - -
- ); - } return (
0} + onRemove={onRemove} />
); @@ -62,7 +57,7 @@ export function MetricsEditor({ fields, metrics, onChange, allowMultipleMetrics, } function addMetric() { - onChange([...metrics, {}]); + onChange([...metrics, { type: AGG_TYPE.AVG }]); } function renderAddMetricButton() { @@ -71,7 +66,7 @@ export function MetricsEditor({ fields, metrics, onChange, allowMultipleMetrics, } return ( - <> + @@ -81,7 +76,7 @@ export function MetricsEditor({ fields, metrics, onChange, allowMultipleMetrics, /> - + ); } @@ -93,16 +88,3 @@ export function MetricsEditor({ fields, metrics, onChange, allowMultipleMetrics,
); } - -MetricsEditor.propTypes = { - metrics: PropTypes.array, - fields: PropTypes.array, - onChange: PropTypes.func.isRequired, - allowMultipleMetrics: PropTypes.bool, - metricsFilter: PropTypes.func, -}; - -MetricsEditor.defaultProps = { - metrics: [DEFAULT_METRIC], - allowMultipleMetrics: true, -}; diff --git a/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.test.js b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.test.js index 3cd8a3c42879..e0e1556ecde0 100644 --- a/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.test.js +++ b/x-pack/plugins/maps/public/connected_components/layer_panel/join_editor/resources/metrics_expression.test.js @@ -4,12 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -jest.mock('../../../../components/metric_editor', () => ({ - MetricsEditor: () => { - return
mockMetricsEditor
; - }, -})); - import React from 'react'; import { shallow } from 'enzyme'; import { MetricsExpression } from './metrics_expression'; diff --git a/x-pack/plugins/maps/public/lazy_load_bundle/index.ts b/x-pack/plugins/maps/public/lazy_load_bundle/index.ts index 5f2a640aa9d0..03752a1c3e11 100644 --- a/x-pack/plugins/maps/public/lazy_load_bundle/index.ts +++ b/x-pack/plugins/maps/public/lazy_load_bundle/index.ts @@ -7,7 +7,7 @@ import { AnyAction } from 'redux'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { IndexPatternsContract } from 'src/plugins/data/public/index_patterns'; -import { ReactElement } from 'react'; +import { AppMountContext, AppMountParameters } from 'kibana/public'; import { IndexPattern } from 'src/plugins/data/public'; import { Embeddable, IContainer } from '../../../../../src/plugins/embeddable/public'; import { LayerDescriptor } from '../../common/descriptor_types'; @@ -40,7 +40,7 @@ interface LazyLoadedMapModules { initialLayers?: LayerDescriptor[] ) => LayerDescriptor[]; mergeInputWithSavedMap: any; - renderApp: (context: unknown, params: unknown) => ReactElement; + renderApp: (context: AppMountContext, params: AppMountParameters) => Promise<() => void>; createSecurityLayerDescriptors: ( indexPatternId: string, indexPatternTitle: string @@ -57,7 +57,6 @@ export async function lazyLoadMapModules(): Promise { loadModulesPromise = new Promise(async (resolve) => { const { - // @ts-expect-error getMapsSavedObjectLoader, getQueryableUniqueIndexPatternIds, MapEmbeddable, @@ -68,7 +67,6 @@ export async function lazyLoadMapModules(): Promise { addLayerWithoutDataSync, getInitialLayers, mergeInputWithSavedMap, - // @ts-expect-error renderApp, createSecurityLayerDescriptors, registerLayerWizard, diff --git a/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts b/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts index e55160383a8f..28f5acdc1765 100644 --- a/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts +++ b/x-pack/plugins/maps/public/lazy_load_bundle/lazy/index.ts @@ -7,7 +7,6 @@ // These are map-dependencies of the embeddable. // By lazy-loading these, the Maps-app can register the embeddable when the plugin mounts, without actually pulling all the code. -// @ts-expect-error export * from '../../routing/bootstrap/services/gis_map_saved_object_loader'; export * from '../../embeddable/map_embeddable'; export * from '../../kibana_services'; @@ -16,7 +15,6 @@ export * from '../../actions'; export * from '../../selectors/map_selectors'; export * from '../../routing/bootstrap/get_initial_layers'; export * from '../../embeddable/merge_input_with_saved_map'; -// @ts-expect-error export * from '../../routing/maps_router'; export * from '../../classes/layers/solution_layers/security'; export { registerLayerWizard } from '../../classes/layers/layer_wizard_registry'; diff --git a/x-pack/plugins/maps/public/plugin.ts b/x-pack/plugins/maps/public/plugin.ts index b08135b4e486..00ee7f376efc 100644 --- a/x-pack/plugins/maps/public/plugin.ts +++ b/x-pack/plugins/maps/public/plugin.ts @@ -123,7 +123,6 @@ export class MapsPlugin icon: `plugins/${APP_ID}/icon.svg`, euiIconType: APP_ICON, category: DEFAULT_APP_CATEGORIES.kibana, - // @ts-expect-error async mount(context, params) { const { renderApp } = await lazyLoadMapModules(); return renderApp(context, params); diff --git a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.js b/x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.ts similarity index 87% rename from x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.js rename to x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.ts index b47f83d5a666..e828dc88409c 100644 --- a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.js +++ b/x-pack/plugins/maps/public/routing/bootstrap/get_initial_layers.ts @@ -15,15 +15,19 @@ import '../../classes/sources/es_pew_pew_source'; import '../../classes/sources/kibana_regionmap_source'; import '../../classes/sources/es_geo_grid_source'; import '../../classes/sources/xyz_tms_source'; +import { LayerDescriptor } from '../../../common/descriptor_types'; +// @ts-expect-error import { KibanaTilemapSource } from '../../classes/sources/kibana_tilemap_source'; import { TileLayer } from '../../classes/layers/tile_layer/tile_layer'; +// @ts-expect-error import { EMSTMSSource } from '../../classes/sources/ems_tms_source'; +// @ts-expect-error import { VectorTileLayer } from '../../classes/layers/vector_tile_layer/vector_tile_layer'; import { getIsEmsEnabled, getToasts } from '../../kibana_services'; import { INITIAL_LAYERS_KEY } from '../../../common/constants'; import { getKibanaTileMap } from '../../meta'; -export function getInitialLayers(layerListJSON, initialLayers = []) { +export function getInitialLayers(layerListJSON?: string, initialLayers: LayerDescriptor[] = []) { if (layerListJSON) { return JSON.parse(layerListJSON); } @@ -58,9 +62,10 @@ export function getInitialLayersFromUrlParam() { try { let mapInitLayers = mapAppParams.get(INITIAL_LAYERS_KEY); - if (mapInitLayers[mapInitLayers.length - 1] === '#') { - mapInitLayers = mapInitLayers.substr(0, mapInitLayers.length - 1); + if (mapInitLayers![mapInitLayers!.length - 1] === '#') { + mapInitLayers = mapInitLayers!.substr(0, mapInitLayers!.length - 1); } + // @ts-ignore return rison.decode_array(mapInitLayers); } catch (e) { getToasts().addWarning({ diff --git a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_query.js b/x-pack/plugins/maps/public/routing/bootstrap/get_initial_query.ts similarity index 73% rename from x-pack/plugins/maps/public/routing/bootstrap/get_initial_query.js rename to x-pack/plugins/maps/public/routing/bootstrap/get_initial_query.ts index 1f2cf2707762..43293d152dbf 100644 --- a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_query.js +++ b/x-pack/plugins/maps/public/routing/bootstrap/get_initial_query.ts @@ -5,8 +5,15 @@ */ import { getData } from '../../kibana_services'; +import { MapsAppState } from '../state_syncing/app_state_manager'; -export function getInitialQuery({ mapStateJSON, appState = {} }) { +export function getInitialQuery({ + mapStateJSON, + appState = {}, +}: { + mapStateJSON?: string; + appState: MapsAppState; +}) { if (appState.query) { return appState.query; } diff --git a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_refresh_config.js b/x-pack/plugins/maps/public/routing/bootstrap/get_initial_refresh_config.ts similarity index 81% rename from x-pack/plugins/maps/public/routing/bootstrap/get_initial_refresh_config.js rename to x-pack/plugins/maps/public/routing/bootstrap/get_initial_refresh_config.ts index d7b3bbf5b4ab..7d759cb25052 100644 --- a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_refresh_config.js +++ b/x-pack/plugins/maps/public/routing/bootstrap/get_initial_refresh_config.ts @@ -4,10 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ +import { QueryState } from 'src/plugins/data/public'; import { getUiSettings } from '../../kibana_services'; import { UI_SETTINGS } from '../../../../../../src/plugins/data/public'; -export function getInitialRefreshConfig({ mapStateJSON, globalState = {} }) { +export function getInitialRefreshConfig({ + mapStateJSON, + globalState = {}, +}: { + mapStateJSON?: string; + globalState: QueryState; +}) { const uiSettings = getUiSettings(); if (mapStateJSON) { diff --git a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_time_filters.js b/x-pack/plugins/maps/public/routing/bootstrap/get_initial_time_filters.ts similarity index 75% rename from x-pack/plugins/maps/public/routing/bootstrap/get_initial_time_filters.js rename to x-pack/plugins/maps/public/routing/bootstrap/get_initial_time_filters.ts index 9c11dabe0392..549cc154fe48 100644 --- a/x-pack/plugins/maps/public/routing/bootstrap/get_initial_time_filters.js +++ b/x-pack/plugins/maps/public/routing/bootstrap/get_initial_time_filters.ts @@ -4,9 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ +import { QueryState } from 'src/plugins/data/public'; import { getUiSettings } from '../../kibana_services'; -export function getInitialTimeFilters({ mapStateJSON, globalState }) { +export function getInitialTimeFilters({ + mapStateJSON, + globalState, +}: { + mapStateJSON?: string; + globalState: QueryState; +}) { if (mapStateJSON) { const mapState = JSON.parse(mapStateJSON); if (mapState.timeFilters) { diff --git a/x-pack/plugins/maps/public/routing/bootstrap/services/gis_map_saved_object_loader.js b/x-pack/plugins/maps/public/routing/bootstrap/services/gis_map_saved_object_loader.ts similarity index 100% rename from x-pack/plugins/maps/public/routing/bootstrap/services/gis_map_saved_object_loader.js rename to x-pack/plugins/maps/public/routing/bootstrap/services/gis_map_saved_object_loader.ts diff --git a/x-pack/plugins/maps/public/routing/bootstrap/services/saved_gis_map.ts b/x-pack/plugins/maps/public/routing/bootstrap/services/saved_gis_map.ts index 6f8e7777f671..511f015b0ff8 100644 --- a/x-pack/plugins/maps/public/routing/bootstrap/services/saved_gis_map.ts +++ b/x-pack/plugins/maps/public/routing/bootstrap/services/saved_gis_map.ts @@ -27,7 +27,6 @@ import { copyPersistentState } from '../../../reducers/util'; // @ts-expect-error import { extractReferences, injectReferences } from '../../../../common/migrations/references'; import { getExistingMapPath, MAP_SAVED_OBJECT_TYPE } from '../../../../common/constants'; -// @ts-expect-error import { getStore } from '../../store_operations'; import { MapStoreState } from '../../../reducers/store'; import { LayerDescriptor } from '../../../../common/descriptor_types'; diff --git a/x-pack/plugins/maps/public/routing/maps_router.js b/x-pack/plugins/maps/public/routing/maps_router.tsx similarity index 80% rename from x-pack/plugins/maps/public/routing/maps_router.js rename to x-pack/plugins/maps/public/routing/maps_router.tsx index f0f5234e3f98..5291d9c36116 100644 --- a/x-pack/plugins/maps/public/routing/maps_router.js +++ b/x-pack/plugins/maps/public/routing/maps_router.tsx @@ -6,8 +6,10 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import { Router, Switch, Route, Redirect } from 'react-router-dom'; +import { Router, Switch, Route, Redirect, RouteComponentProps } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; +import { Provider } from 'react-redux'; +import { AppMountContext, AppMountParameters } from 'kibana/public'; import { getCoreChrome, getCoreI18n, @@ -18,16 +20,19 @@ import { import { createKbnUrlStateStorage, withNotifyOnErrors, + IKbnUrlStateStorage, } from '../../../../../src/plugins/kibana_utils/public'; import { getStore } from './store_operations'; -import { Provider } from 'react-redux'; import { LoadListAndRender } from './routes/list/load_list_and_render'; import { LoadMapAndRender } from './routes/maps_app/load_map_and_render'; -export let goToSpecifiedPath; -export let kbnUrlStateStorage; +export let goToSpecifiedPath: (path: string) => void; +export let kbnUrlStateStorage: IKbnUrlStateStorage; -export async function renderApp(context, { appBasePath, element, history, onAppLeave }) { +export async function renderApp( + context: AppMountContext, + { appBasePath, element, history, onAppLeave }: AppMountParameters +) { goToSpecifiedPath = (path) => history.push(path); kbnUrlStateStorage = createKbnUrlStateStorage({ useHash: false, @@ -42,11 +47,19 @@ export async function renderApp(context, { appBasePath, element, history, onAppL }; } -const App = ({ history, appBasePath, onAppLeave }) => { +interface Props { + history: AppMountParameters['history'] | RouteComponentProps['history']; + appBasePath: AppMountParameters['appBasePath']; + onAppLeave: AppMountParameters['onAppLeave']; +} + +const App: React.FC = ({ history, appBasePath, onAppLeave }) => { const store = getStore(); const I18nContext = getCoreI18n().Context; - const stateTransfer = getEmbeddableService()?.getStateTransfer(history); + const stateTransfer = getEmbeddableService()?.getStateTransfer( + history as AppMountParameters['history'] + ); const { originatingApp } = stateTransfer?.getIncomingEditorState({ keysToRemoveAfterFetch: ['originatingApp'] }) || {}; @@ -66,7 +79,7 @@ const App = ({ history, appBasePath, onAppLeave }) => { return ( - + getMapsSavedObjectLoader().find(search, this.state.listingLimit); + _find = (search: string) => getMapsSavedObjectLoader().find(search, this.state.listingLimit); - _delete = (ids) => getMapsSavedObjectLoader().delete(ids); + _delete = (ids: string[]) => getMapsSavedObjectLoader().delete(ids); debouncedFetch = _.debounce(async (filter) => { const response = await this._find(filter); @@ -135,10 +163,10 @@ export class MapsListView extends React.Component { this.setState({ showDeleteModal: true }); }; - onTableChange = ({ page, sort = {} }) => { + onTableChange = ({ page, sort }: CriteriaWithPagination) => { const { index: pageIndex, size: pageSize } = page; - let { field: sortField, direction: sortDirection } = sort; + let { field: sortField, direction: sortDirection } = sort || {}; // 3rd sorting state that is not captured by sort - native order (no sort) // when switching from desc to asc for the same field - use native order @@ -147,8 +175,8 @@ export class MapsListView extends React.Component { this.state.sortDirection === 'desc' && sortDirection === 'asc' ) { - sortField = null; - sortDirection = null; + sortField = undefined; + sortDirection = undefined; } this.setState({ @@ -165,8 +193,8 @@ export class MapsListView extends React.Component { if (this.state.sortField) { itemsCopy.sort((a, b) => { - const fieldA = _.get(a, this.state.sortField, ''); - const fieldB = _.get(b, this.state.sortField, ''); + const fieldA = _.get(a, this.state.sortField!, ''); + const fieldB = _.get(b, this.state.sortField!, ''); let order = 1; if (this.state.sortDirection === 'desc') { order = -1; @@ -320,7 +348,7 @@ export class MapsListView extends React.Component { } renderTable() { - const tableColumns = [ + const tableColumns: Array> = [ { field: 'title', name: i18n.translate('xpack.maps.mapListing.titleFieldTitle', { @@ -329,7 +357,7 @@ export class MapsListView extends React.Component { sortable: true, render: (field, record) => ( { + onClick={(e: MouseEvent) => { e.preventDefault(); goToSpecifiedPath(`/map/${record.id}`); }} @@ -355,12 +383,12 @@ export class MapsListView extends React.Component { pageSizeOptions: [10, 20, 50], }; - let selection = false; + let selection; if (!this.state.readOnly) { selection = { - onSelectionChange: (selection) => { + onSelectionChange: (s: SelectionItem[]) => { this.setState({ - selectedIds: selection.map((item) => { + selectedIds: s.map((item) => { return item.id; }), }); @@ -368,11 +396,11 @@ export class MapsListView extends React.Component { }; } - const sorting = {}; + const sorting: EuiTableSortingType = {}; if (this.state.sortField) { sorting.sort = { field: this.state.sortField, - direction: this.state.sortDirection, + direction: this.state.sortDirection!, }; } const items = this.state.items.length === 0 ? [] : this.getPageOfItems(); diff --git a/x-pack/plugins/maps/public/routing/routes/maps_app/get_breadcrumbs.tsx b/x-pack/plugins/maps/public/routing/routes/maps_app/get_breadcrumbs.tsx index 1ccf890597ed..149c04b414c1 100644 --- a/x-pack/plugins/maps/public/routing/routes/maps_app/get_breadcrumbs.tsx +++ b/x-pack/plugins/maps/public/routing/routes/maps_app/get_breadcrumbs.tsx @@ -6,7 +6,6 @@ import { i18n } from '@kbn/i18n'; import { getNavigateToApp } from '../../../kibana_services'; -// @ts-expect-error import { goToSpecifiedPath } from '../../maps_router'; export const unsavedChangesWarning = i18n.translate( @@ -25,7 +24,7 @@ export function getBreadcrumbs({ title: string; getHasUnsavedChanges: () => boolean; originatingApp?: string; - getAppNameFromId?: (id: string) => string; + getAppNameFromId?: (id: string) => string | undefined; }) { const breadcrumbs = []; if (originatingApp && getAppNameFromId) { diff --git a/x-pack/plugins/maps/public/routing/routes/maps_app/index.js b/x-pack/plugins/maps/public/routing/routes/maps_app/index.ts similarity index 62% rename from x-pack/plugins/maps/public/routing/routes/maps_app/index.js rename to x-pack/plugins/maps/public/routing/routes/maps_app/index.ts index 326db7289e60..812d7fcf3098 100644 --- a/x-pack/plugins/maps/public/routing/routes/maps_app/index.js +++ b/x-pack/plugins/maps/public/routing/routes/maps_app/index.ts @@ -5,6 +5,9 @@ */ import { connect } from 'react-redux'; +import { ThunkDispatch } from 'redux-thunk'; +import { AnyAction } from 'redux'; +import { Filter, Query, TimeRange } from 'src/plugins/data/public'; import { MapsAppView } from './maps_app_view'; import { getFlyoutDisplay, getIsFullScreen } from '../../../selectors/ui_selectors'; import { @@ -33,8 +36,15 @@ import { import { FLYOUT_STATE } from '../../../reducers/ui'; import { getMapsCapabilities } from '../../../kibana_services'; import { getInspectorAdapters } from '../../../reducers/non_serializable_instances'; +import { MapStoreState } from '../../../reducers/store'; +import { + MapRefreshConfig, + MapCenterAndZoom, + LayerDescriptor, +} from '../../../../common/descriptor_types'; +import { MapSettings } from '../../../reducers/map'; -function mapStateToProps(state = {}) { +function mapStateToProps(state: MapStoreState) { return { isFullScreen: getIsFullScreen(state), isOpenSettingsDisabled: getFlyoutDisplay(state) !== FLYOUT_STATE.NONE, @@ -50,9 +60,19 @@ function mapStateToProps(state = {}) { }; } -function mapDispatchToProps(dispatch) { +function mapDispatchToProps(dispatch: ThunkDispatch) { return { - dispatchSetQuery: ({ forceRefresh, filters, query, timeFilters }) => { + dispatchSetQuery: ({ + forceRefresh, + filters, + query, + timeFilters, + }: { + filters?: Filter[]; + query?: Query; + timeFilters?: TimeRange; + forceRefresh?: boolean; + }) => { dispatch( setQuery({ filters, @@ -62,12 +82,13 @@ function mapDispatchToProps(dispatch) { }) ); }, - setRefreshConfig: (refreshConfig) => dispatch(setRefreshConfig(refreshConfig)), - replaceLayerList: (layerList) => dispatch(replaceLayerList(layerList)), - setGotoWithCenter: (latLonZoom) => dispatch(setGotoWithCenter(latLonZoom)), - setMapSettings: (mapSettings) => dispatch(setMapSettings(mapSettings)), - setIsLayerTOCOpen: (isLayerTOCOpen) => dispatch(setIsLayerTOCOpen(isLayerTOCOpen)), - setOpenTOCDetails: (openTOCDetails) => dispatch(setOpenTOCDetails(openTOCDetails)), + setRefreshConfig: (refreshConfig: MapRefreshConfig) => + dispatch(setRefreshConfig(refreshConfig)), + replaceLayerList: (layerList: LayerDescriptor[]) => dispatch(replaceLayerList(layerList)), + setGotoWithCenter: (latLonZoom: MapCenterAndZoom) => dispatch(setGotoWithCenter(latLonZoom)), + setMapSettings: (mapSettings: MapSettings) => dispatch(setMapSettings(mapSettings)), + setIsLayerTOCOpen: (isLayerTOCOpen: boolean) => dispatch(setIsLayerTOCOpen(isLayerTOCOpen)), + setOpenTOCDetails: (openTOCDetails: string[]) => dispatch(setOpenTOCDetails(openTOCDetails)), clearUi: () => { dispatch(setSelectedLayer(null)); dispatch(updateFlyout(FLYOUT_STATE.NONE)); diff --git a/x-pack/plugins/maps/public/routing/routes/maps_app/load_map_and_render.js b/x-pack/plugins/maps/public/routing/routes/maps_app/load_map_and_render.tsx similarity index 75% rename from x-pack/plugins/maps/public/routing/routes/maps_app/load_map_and_render.js rename to x-pack/plugins/maps/public/routing/routes/maps_app/load_map_and_render.tsx index eebbb1758282..7ab138300dc4 100644 --- a/x-pack/plugins/maps/public/routing/routes/maps_app/load_map_and_render.js +++ b/x-pack/plugins/maps/public/routing/routes/maps_app/load_map_and_render.tsx @@ -5,15 +5,31 @@ */ import React from 'react'; -import { MapsAppView } from '.'; -import { getMapsSavedObjectLoader } from '../../bootstrap/services/gis_map_saved_object_loader'; -import { getCoreChrome, getToasts } from '../../../kibana_services'; import { i18n } from '@kbn/i18n'; import { Redirect } from 'react-router-dom'; +import { AppMountParameters } from 'kibana/public'; +import { EmbeddableStateTransfer } from 'src/plugins/embeddable/public'; +import { getCoreChrome, getToasts } from '../../../kibana_services'; +import { getMapsSavedObjectLoader } from '../../bootstrap/services/gis_map_saved_object_loader'; +import { MapsAppView } from '.'; +import { ISavedGisMap } from '../../bootstrap/services/saved_gis_map'; + +interface Props { + savedMapId?: string; + onAppLeave: AppMountParameters['onAppLeave']; + stateTransfer: EmbeddableStateTransfer; + originatingApp?: string; +} + +interface State { + savedMap?: ISavedGisMap; + failedToLoad: boolean; +} -export const LoadMapAndRender = class extends React.Component { - state = { - savedMap: null, +export const LoadMapAndRender = class extends React.Component { + _isMounted: boolean = false; + state: State = { + savedMap: undefined, failedToLoad: false, }; diff --git a/x-pack/plugins/maps/public/routing/routes/maps_app/maps_app_view.js b/x-pack/plugins/maps/public/routing/routes/maps_app/maps_app_view.tsx similarity index 73% rename from x-pack/plugins/maps/public/routing/routes/maps_app/maps_app_view.js rename to x-pack/plugins/maps/public/routing/routes/maps_app/maps_app_view.tsx index 485b0ed7682f..b3377547b2dd 100644 --- a/x-pack/plugins/maps/public/routing/routes/maps_app/maps_app_view.js +++ b/x-pack/plugins/maps/public/routing/routes/maps_app/maps_app_view.tsx @@ -7,6 +7,9 @@ import React from 'react'; import 'mapbox-gl/dist/mapbox-gl.css'; import _ from 'lodash'; +import { AppLeaveAction, AppMountParameters } from 'kibana/public'; +import { EmbeddableStateTransfer, Adapters } from 'src/plugins/embeddable/public'; +import { Subscription } from 'rxjs'; import { DEFAULT_IS_LAYER_TOC_OPEN } from '../../../reducers/ui'; import { getData, @@ -23,29 +26,91 @@ import { getGlobalState, updateGlobalState, startGlobalStateSyncing, + MapsGlobalState, } from '../../state_syncing/global_sync'; import { AppStateManager } from '../../state_syncing/app_state_manager'; import { startAppStateSyncing } from '../../state_syncing/app_sync'; -import { esFilters } from '../../../../../../../src/plugins/data/public'; +import { + esFilters, + Filter, + Query, + TimeRange, + IndexPattern, + SavedQuery, + QueryStateChange, + QueryState, +} from '../../../../../../../src/plugins/data/public'; import { MapContainer } from '../../../connected_components/map_container'; import { getIndexPatternsFromIds } from '../../../index_pattern_util'; import { getTopNavConfig } from './top_nav_config'; import { getBreadcrumbs, unsavedChangesWarning } from './get_breadcrumbs'; +import { + LayerDescriptor, + MapRefreshConfig, + MapCenterAndZoom, + MapQuery, +} from '../../../../common/descriptor_types'; +import { MapSettings } from '../../../reducers/map'; +import { ISavedGisMap } from '../../bootstrap/services/saved_gis_map'; + +interface Props { + savedMap: ISavedGisMap; + onAppLeave: AppMountParameters['onAppLeave']; + stateTransfer: EmbeddableStateTransfer; + originatingApp?: string; + layerListConfigOnly: LayerDescriptor[]; + replaceLayerList: (layerList: LayerDescriptor[]) => void; + filters: Filter[]; + isFullScreen: boolean; + isOpenSettingsDisabled: boolean; + enableFullScreen: () => void; + openMapSettings: () => void; + inspectorAdapters: Adapters; + nextIndexPatternIds: string[]; + dispatchSetQuery: ({ + forceRefresh, + filters, + query, + timeFilters, + }: { + filters?: Filter[]; + query?: Query; + timeFilters?: TimeRange; + forceRefresh?: boolean; + }) => void; + timeFilters: TimeRange; + refreshConfig: MapRefreshConfig; + setRefreshConfig: (refreshConfig: MapRefreshConfig) => void; + isSaveDisabled: boolean; + clearUi: () => void; + setGotoWithCenter: (latLonZoom: MapCenterAndZoom) => void; + setMapSettings: (mapSettings: MapSettings) => void; + setIsLayerTOCOpen: (isLayerTOCOpen: boolean) => void; + setOpenTOCDetails: (openTOCDetails: string[]) => void; + query: MapQuery | undefined; +} -export class MapsAppView extends React.Component { - _globalSyncUnsubscribe = null; - _globalSyncChangeMonitorSubscription = null; - _appSyncUnsubscribe = null; +interface State { + initialized: boolean; + initialLayerListConfig?: LayerDescriptor[]; + indexPatterns: IndexPattern[]; + savedQuery?: SavedQuery; + originatingApp?: string; +} + +export class MapsAppView extends React.Component { + _globalSyncUnsubscribe: (() => void) | null = null; + _globalSyncChangeMonitorSubscription: Subscription | null = null; + _appSyncUnsubscribe: (() => void) | null = null; _appStateManager = new AppStateManager(); - _prevIndexPatternIds = null; + _prevIndexPatternIds: string[] | null = null; + _isMounted: boolean = false; - constructor(props) { + constructor(props: Props) { super(props); this.state = { indexPatterns: [], initialized: false, - savedQuery: '', - initialLayerListConfig: null, // tracking originatingApp in state so the connection can be broken by users originatingApp: props.originatingApp, }; @@ -60,10 +125,11 @@ export class MapsAppView extends React.Component { this._updateFromGlobalState ); - const initialSavedQuery = this._appStateManager.getAppState().savedQuery; - if (initialSavedQuery) { - this._updateStateFromSavedQuery(initialSavedQuery); - } + // savedQuery must be fetched from savedQueryId + // const initialSavedQuery = this._appStateManager.getAppState().savedQuery; + // if (initialSavedQuery) { + // this._updateStateFromSavedQuery(initialSavedQuery as SavedQuery); + // } this._initMap(); @@ -72,10 +138,10 @@ export class MapsAppView extends React.Component { this.props.onAppLeave((actions) => { if (this._hasUnsavedChanges()) { if (!window.confirm(unsavedChangesWarning)) { - return; + return {} as AppLeaveAction; } } - return actions.default(); + return actions.default() as AppLeaveAction; }); } @@ -121,7 +187,13 @@ export class MapsAppView extends React.Component { getCoreChrome().setBreadcrumbs(breadcrumbs); }; - _updateFromGlobalState = ({ changes, state: globalState }) => { + _updateFromGlobalState = ({ + changes, + state: globalState, + }: { + changes: QueryStateChange; + state: QueryState; + }) => { if (!this.state.initialized || !changes || !globalState) { return; } @@ -144,7 +216,17 @@ export class MapsAppView extends React.Component { } } - _onQueryChange = ({ filters, query, time, forceRefresh = false }) => { + _onQueryChange = ({ + filters, + query, + time, + forceRefresh = false, + }: { + filters?: Filter[]; + query?: Query; + time?: TimeRange; + forceRefresh?: boolean; + }) => { const { filterManager } = getData().query; if (filters) { @@ -165,7 +247,9 @@ export class MapsAppView extends React.Component { }); // sync globalState - const updatedGlobalState = { filters: filterManager.getGlobalFilters() }; + const updatedGlobalState: MapsGlobalState = { + filters: filterManager.getGlobalFilters(), + }; if (time) { updatedGlobalState.time = time; } @@ -173,7 +257,7 @@ export class MapsAppView extends React.Component { }; _initMapAndLayerSettings() { - const globalState = getGlobalState(); + const globalState: MapsGlobalState = getGlobalState(); const mapStateJSON = this.props.savedMap.mapStateJSON; let savedObjectFilters = []; @@ -219,14 +303,14 @@ export class MapsAppView extends React.Component { }); } - _onFiltersChange = (filters) => { + _onFiltersChange = (filters: Filter[]) => { this._onQueryChange({ filters, }); }; // mapRefreshConfig: MapRefreshConfig - _onRefreshConfigChange(mapRefreshConfig) { + _onRefreshConfigChange(mapRefreshConfig: MapRefreshConfig) { this.props.setRefreshConfig(mapRefreshConfig); updateGlobalState( { @@ -239,9 +323,9 @@ export class MapsAppView extends React.Component { ); } - _updateStateFromSavedQuery = (savedQuery) => { + _updateStateFromSavedQuery = (savedQuery: SavedQuery) => { this.setState({ savedQuery: { ...savedQuery } }); - this._appStateManager.setQueryAndFilters({ savedQuery }); + this._appStateManager.setQueryAndFilters({ savedQueryId: savedQuery.id }); const { filterManager } = getData().query; const savedQueryFilters = savedQuery.attributes.filters || []; @@ -328,7 +412,13 @@ export class MapsAppView extends React.Component { dateRangeTo={this.props.timeFilters.to} isRefreshPaused={this.props.refreshConfig.isPaused} refreshInterval={this.props.refreshConfig.interval} - onRefreshChange={({ isPaused, refreshInterval }) => { + onRefreshChange={({ + isPaused, + refreshInterval, + }: { + isPaused: boolean; + refreshInterval: number; + }) => { this._onRefreshConfigChange({ isPaused, interval: refreshInterval, @@ -337,14 +427,14 @@ export class MapsAppView extends React.Component { showSearchBar={true} showFilterBar={true} showDatePicker={true} - showSaveQuery={getMapsCapabilities().saveQuery} + showSaveQuery={!!getMapsCapabilities().saveQuery} savedQuery={this.state.savedQuery} onSaved={this._updateStateFromSavedQuery} onSavedQueryUpdated={this._updateStateFromSavedQuery} onClearSavedQuery={() => { const { filterManager, queryString } = getData().query; - this.setState({ savedQuery: '' }); - this._appStateManager.setQueryAndFilters({ savedQuery: '' }); + this.setState({ savedQuery: undefined }); + this._appStateManager.setQueryAndFilters({ savedQueryId: '' }); this._onQueryChange({ filters: filterManager.getGlobalFilters(), query: queryString.getDefaultQuery(), @@ -354,7 +444,7 @@ export class MapsAppView extends React.Component { ); } - _addFilter = (newFilters) => { + _addFilter = async (newFilters: Filter[]) => { newFilters.forEach((filter) => { filter.$state = { store: esFilters.FilterStateStore.APP_STATE }; }); diff --git a/x-pack/plugins/maps/public/routing/routes/maps_app/top_nav_config.tsx b/x-pack/plugins/maps/public/routing/routes/maps_app/top_nav_config.tsx index 497c87ad533a..47f41f2b76f3 100644 --- a/x-pack/plugins/maps/public/routing/routes/maps_app/top_nav_config.tsx +++ b/x-pack/plugins/maps/public/routing/routes/maps_app/top_nav_config.tsx @@ -21,7 +21,6 @@ import { showSaveModal, } from '../../../../../../../src/plugins/saved_objects/public'; import { MAP_SAVED_OBJECT_TYPE } from '../../../../common/constants'; -// @ts-expect-error import { goToSpecifiedPath } from '../../maps_router'; import { ISavedGisMap } from '../../bootstrap/services/saved_gis_map'; import { EmbeddableStateTransfer } from '../../../../../../../src/plugins/embeddable/public'; diff --git a/x-pack/plugins/maps/public/routing/state_syncing/app_state_manager.js b/x-pack/plugins/maps/public/routing/state_syncing/app_state_manager.ts similarity index 58% rename from x-pack/plugins/maps/public/routing/state_syncing/app_state_manager.js rename to x-pack/plugins/maps/public/routing/state_syncing/app_state_manager.ts index 4cdba13bd85d..122b50f823a9 100644 --- a/x-pack/plugins/maps/public/routing/state_syncing/app_state_manager.js +++ b/x-pack/plugins/maps/public/routing/state_syncing/app_state_manager.ts @@ -5,20 +5,27 @@ */ import { Subject } from 'rxjs'; +import { Filter, Query } from 'src/plugins/data/public'; + +export interface MapsAppState { + query?: Query | null; + savedQueryId?: string; + filters?: Filter[]; +} export class AppStateManager { - _query = ''; - _savedQuery = ''; - _filters = []; + _query: Query | null = null; + _savedQueryId: string = ''; + _filters: Filter[] = []; _updated$ = new Subject(); - setQueryAndFilters({ query, savedQuery, filters }) { + setQueryAndFilters({ query, savedQueryId, filters }: MapsAppState) { if (query && this._query !== query) { this._query = query; } - if (savedQuery && this._savedQuery !== savedQuery) { - this._savedQuery = savedQuery; + if (savedQueryId && this._savedQueryId !== savedQueryId) { + this._savedQueryId = savedQueryId; } if (filters && this._filters !== filters) { this._filters = filters; @@ -34,10 +41,10 @@ export class AppStateManager { return this._filters; } - getAppState() { + getAppState(): MapsAppState { return { query: this._query, - savedQuery: this._savedQuery, + savedQueryId: this._savedQueryId, filters: this._filters, }; } diff --git a/x-pack/plugins/maps/public/routing/state_syncing/app_sync.js b/x-pack/plugins/maps/public/routing/state_syncing/app_sync.ts similarity index 88% rename from x-pack/plugins/maps/public/routing/state_syncing/app_sync.js rename to x-pack/plugins/maps/public/routing/state_syncing/app_sync.ts index 60e8dc9cd574..b346822913be 100644 --- a/x-pack/plugins/maps/public/routing/state_syncing/app_sync.js +++ b/x-pack/plugins/maps/public/routing/state_syncing/app_sync.ts @@ -4,13 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { connectToQueryState, esFilters } from '../../../../../../src/plugins/data/public'; -import { syncState } from '../../../../../../src/plugins/kibana_utils/public'; import { map } from 'rxjs/operators'; +import { connectToQueryState, esFilters } from '../../../../../../src/plugins/data/public'; +import { syncState, BaseStateContainer } from '../../../../../../src/plugins/kibana_utils/public'; import { getData } from '../../kibana_services'; import { kbnUrlStateStorage } from '../maps_router'; +import { AppStateManager } from './app_state_manager'; -export function startAppStateSyncing(appStateManager) { +export function startAppStateSyncing(appStateManager: AppStateManager) { // get appStateContainer // sync app filters with app state container from data.query to state container const { query } = getData(); @@ -19,7 +20,7 @@ export function startAppStateSyncing(appStateManager) { // clear app state filters to prevent application filters from other applications being transfered to maps query.filterManager.setAppFilters([]); - const stateContainer = { + const stateContainer: BaseStateContainer = { get: () => ({ query: appStateManager.getQuery(), filters: appStateManager.getFilters(), @@ -48,6 +49,7 @@ export function startAppStateSyncing(appStateManager) { // merge initial state from app state container and current state in url const initialAppState = { ...stateContainer.get(), + // @ts-ignore ...kbnUrlStateStorage.get('_a'), }; // trigger state update. actually needed in case some data was in url diff --git a/x-pack/plugins/maps/public/routing/state_syncing/global_sync.ts b/x-pack/plugins/maps/public/routing/state_syncing/global_sync.ts index 4e17241752f5..1e779831c5e0 100644 --- a/x-pack/plugins/maps/public/routing/state_syncing/global_sync.ts +++ b/x-pack/plugins/maps/public/routing/state_syncing/global_sync.ts @@ -3,27 +3,30 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - +import { TimeRange, RefreshInterval, Filter } from 'src/plugins/data/public'; import { syncQueryStateWithUrl } from '../../../../../../src/plugins/data/public'; import { getData } from '../../kibana_services'; -// @ts-ignore import { kbnUrlStateStorage } from '../maps_router'; +export interface MapsGlobalState { + time?: TimeRange; + refreshInterval?: RefreshInterval; + filters?: Filter[]; +} + export function startGlobalStateSyncing() { const { stop } = syncQueryStateWithUrl(getData().query, kbnUrlStateStorage); return stop; } -export function getGlobalState() { - return kbnUrlStateStorage.get('_g'); +export function getGlobalState(): MapsGlobalState { + return kbnUrlStateStorage.get('_g') as MapsGlobalState; } -export function updateGlobalState(newState: unknown, flushUrlState = false) { +export function updateGlobalState(newState: MapsGlobalState, flushUrlState = false) { const globalState = getGlobalState(); kbnUrlStateStorage.set('_g', { - // @ts-ignore ...globalState, - // @ts-ignore ...newState, }); if (flushUrlState) { diff --git a/x-pack/plugins/maps/public/routing/store_operations.js b/x-pack/plugins/maps/public/routing/store_operations.ts similarity index 100% rename from x-pack/plugins/maps/public/routing/store_operations.js rename to x-pack/plugins/maps/public/routing/store_operations.ts diff --git a/x-pack/plugins/ml/common/constants/data_frame_analytics.ts b/x-pack/plugins/ml/common/constants/data_frame_analytics.ts new file mode 100644 index 000000000000..830537cbadbc --- /dev/null +++ b/x-pack/plugins/ml/common/constants/data_frame_analytics.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export const DEFAULT_RESULTS_FIELD = 'ml'; diff --git a/x-pack/plugins/ml/common/types/__mocks__/job_config_farequote.json b/x-pack/plugins/ml/common/types/__mocks__/job_config_farequote.json index 18a49bb3841b..6bc0e55b5aad 100644 --- a/x-pack/plugins/ml/common/types/__mocks__/job_config_farequote.json +++ b/x-pack/plugins/ml/common/types/__mocks__/job_config_farequote.json @@ -69,9 +69,7 @@ "datafeed_id": "datafeed-farequote", "job_id": "farequote", "query_delay": "115823ms", - "indices": [ - "farequote" - ], + "indices": ["farequote"], "query": { "bool": { "must": [ @@ -103,7 +101,7 @@ "buckets": { "date_histogram": { "field": "@timestamp", - "interval": 900000, + "fixed_interval": "15m", "offset": 0, "order": { "_key": "asc" diff --git a/x-pack/plugins/ml/common/types/data_frame_analytics.ts b/x-pack/plugins/ml/common/types/data_frame_analytics.ts index f0aac7504758..60d2ca63dda5 100644 --- a/x-pack/plugins/ml/common/types/data_frame_analytics.ts +++ b/x-pack/plugins/ml/common/types/data_frame_analytics.ts @@ -79,3 +79,9 @@ export interface DataFrameAnalyticsConfig { version: string; allow_lazy_start?: boolean; } + +export enum ANALYSIS_CONFIG_TYPE { + OUTLIER_DETECTION = 'outlier_detection', + REGRESSION = 'regression', + CLASSIFICATION = 'classification', +} diff --git a/x-pack/plugins/ml/common/types/feature_importance.ts b/x-pack/plugins/ml/common/types/feature_importance.ts new file mode 100644 index 000000000000..d2ab9f6c5860 --- /dev/null +++ b/x-pack/plugins/ml/common/types/feature_importance.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export interface ClassFeatureImportance { + class_name: string | boolean; + importance: number; +} +export interface FeatureImportance { + feature_name: string; + importance?: number; + classes?: ClassFeatureImportance[]; +} + +export interface TopClass { + class_name: string; + class_probability: number; + class_score: number; +} + +export type TopClasses = TopClass[]; diff --git a/x-pack/plugins/ml/common/types/file_datavisualizer.ts b/x-pack/plugins/ml/common/types/file_datavisualizer.ts index c997a4e24f86..a8b775c8d5f6 100644 --- a/x-pack/plugins/ml/common/types/file_datavisualizer.ts +++ b/x-pack/plugins/ml/common/types/file_datavisualizer.ts @@ -84,7 +84,12 @@ export interface Settings { } export interface Mappings { - [key: string]: any; + _meta?: { + created_by: string; + }; + properties: { + [key: string]: any; + }; } export interface IngestPipelineWrapper { diff --git a/x-pack/plugins/ml/common/util/analytics_utils.ts b/x-pack/plugins/ml/common/util/analytics_utils.ts new file mode 100644 index 000000000000..d725984a47d6 --- /dev/null +++ b/x-pack/plugins/ml/common/util/analytics_utils.ts @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + AnalysisConfig, + ClassificationAnalysis, + OutlierAnalysis, + RegressionAnalysis, + ANALYSIS_CONFIG_TYPE, +} from '../types/data_frame_analytics'; + +export const isOutlierAnalysis = (arg: any): arg is OutlierAnalysis => { + const keys = Object.keys(arg); + return keys.length === 1 && keys[0] === ANALYSIS_CONFIG_TYPE.OUTLIER_DETECTION; +}; + +export const isRegressionAnalysis = (arg: any): arg is RegressionAnalysis => { + const keys = Object.keys(arg); + return keys.length === 1 && keys[0] === ANALYSIS_CONFIG_TYPE.REGRESSION; +}; + +export const isClassificationAnalysis = (arg: any): arg is ClassificationAnalysis => { + const keys = Object.keys(arg); + return keys.length === 1 && keys[0] === ANALYSIS_CONFIG_TYPE.CLASSIFICATION; +}; + +export const getDependentVar = ( + analysis: AnalysisConfig +): + | RegressionAnalysis['regression']['dependent_variable'] + | ClassificationAnalysis['classification']['dependent_variable'] => { + let depVar = ''; + + if (isRegressionAnalysis(analysis)) { + depVar = analysis.regression.dependent_variable; + } + + if (isClassificationAnalysis(analysis)) { + depVar = analysis.classification.dependent_variable; + } + return depVar; +}; + +export const getPredictionFieldName = ( + analysis: AnalysisConfig +): + | RegressionAnalysis['regression']['prediction_field_name'] + | ClassificationAnalysis['classification']['prediction_field_name'] => { + // If undefined will be defaulted to dependent_variable when config is created + let predictionFieldName; + if (isRegressionAnalysis(analysis) && analysis.regression.prediction_field_name !== undefined) { + predictionFieldName = analysis.regression.prediction_field_name; + } else if ( + isClassificationAnalysis(analysis) && + analysis.classification.prediction_field_name !== undefined + ) { + predictionFieldName = analysis.classification.prediction_field_name; + } + return predictionFieldName; +}; + +export const getDefaultPredictionFieldName = (analysis: AnalysisConfig) => { + return `${getDependentVar(analysis)}_prediction`; +}; +export const getPredictedFieldName = ( + resultsField: string, + analysis: AnalysisConfig, + forSort?: boolean +) => { + // default is 'ml' + const predictionFieldName = getPredictionFieldName(analysis); + const predictedField = `${resultsField}.${ + predictionFieldName ? predictionFieldName : getDefaultPredictionFieldName(analysis) + }`; + return predictedField; +}; diff --git a/x-pack/plugins/ml/common/util/errors.ts b/x-pack/plugins/ml/common/util/errors.ts index 6c5fa7bd75da..a5f89db96cfd 100644 --- a/x-pack/plugins/ml/common/util/errors.ts +++ b/x-pack/plugins/ml/common/util/errors.ts @@ -135,7 +135,14 @@ export const extractErrorProperties = ( typeof error.body.attributes === 'object' && error.body.attributes.body?.status !== undefined ) { - statusCode = error.body.attributes.body?.status; + statusCode = error.body.attributes.body.status; + + if (typeof error.body.attributes.body.error?.reason === 'string') { + return { + message: error.body.attributes.body.error.reason, + statusCode, + }; + } } if (typeof error.body.message === 'string') { diff --git a/x-pack/plugins/ml/public/application/components/data_grid/common.ts b/x-pack/plugins/ml/public/application/components/data_grid/common.ts index 1f0fcb63f019..f252729cc20c 100644 --- a/x-pack/plugins/ml/public/application/components/data_grid/common.ts +++ b/x-pack/plugins/ml/public/application/components/data_grid/common.ts @@ -119,13 +119,14 @@ export const getDataGridSchemasFromFieldTypes = (fieldTypes: FieldTypes, results schema = 'numeric'; } - if ( - field.includes(`${resultsField}.${FEATURE_IMPORTANCE}`) || - field.includes(`${resultsField}.${TOP_CLASSES}`) - ) { + if (field.includes(`${resultsField}.${TOP_CLASSES}`)) { schema = 'json'; } + if (field.includes(`${resultsField}.${FEATURE_IMPORTANCE}`)) { + schema = 'featureImportance'; + } + return { id: field, schema, isSortable }; }); }; @@ -250,10 +251,6 @@ export const useRenderCellValue = ( return cellValue ? 'true' : 'false'; } - if (typeof cellValue === 'object' && cellValue !== null) { - return JSON.stringify(cellValue); - } - return cellValue; }; }, [indexPattern?.fields, pagination.pageIndex, pagination.pageSize, tableItems]); diff --git a/x-pack/plugins/ml/public/application/components/data_grid/data_grid.tsx b/x-pack/plugins/ml/public/application/components/data_grid/data_grid.tsx index d4be2eab13d2..22815fe593d5 100644 --- a/x-pack/plugins/ml/public/application/components/data_grid/data_grid.tsx +++ b/x-pack/plugins/ml/public/application/components/data_grid/data_grid.tsx @@ -5,8 +5,7 @@ */ import { isEqual } from 'lodash'; -import React, { memo, useEffect, FC } from 'react'; - +import React, { memo, useEffect, FC, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { @@ -24,13 +23,16 @@ import { } from '@elastic/eui'; import { CoreSetup } from 'src/core/public'; - import { DEFAULT_SAMPLER_SHARD_SIZE } from '../../../../common/constants/field_histograms'; -import { INDEX_STATUS } from '../../data_frame_analytics/common'; +import { ANALYSIS_CONFIG_TYPE, INDEX_STATUS } from '../../data_frame_analytics/common'; import { euiDataGridStyle, euiDataGridToolbarSettings } from './common'; import { UseIndexDataReturnType } from './types'; +import { DecisionPathPopover } from './feature_importance/decision_path_popover'; +import { TopClasses } from '../../../../common/types/feature_importance'; +import { DEFAULT_RESULTS_FIELD } from '../../../../common/constants/data_frame_analytics'; + // TODO Fix row hovering + bar highlighting // import { hoveredRow$ } from './column_chart'; @@ -41,6 +43,9 @@ export const DataGridTitle: FC<{ title: string }> = ({ title }) => ( ); interface PropsWithoutHeader extends UseIndexDataReturnType { + baseline?: number; + analysisType?: ANALYSIS_CONFIG_TYPE; + resultsField?: string; dataTestSubj: string; toastNotifications: CoreSetup['notifications']['toasts']; } @@ -60,6 +65,7 @@ type Props = PropsWithHeader | PropsWithoutHeader; export const DataGrid: FC = memo( (props) => { const { + baseline, chartsVisible, chartsButtonVisible, columnsWithCharts, @@ -80,8 +86,10 @@ export const DataGrid: FC = memo( toastNotifications, toggleChartVisibility, visibleColumns, + predictionFieldName, + resultsField, + analysisType, } = props; - // TODO Fix row hovering + bar highlighting // const getRowProps = (item: any) => { // return { @@ -90,6 +98,45 @@ export const DataGrid: FC = memo( // }; // }; + const popOverContent = useMemo(() => { + return analysisType === ANALYSIS_CONFIG_TYPE.REGRESSION || + analysisType === ANALYSIS_CONFIG_TYPE.CLASSIFICATION + ? { + featureImportance: ({ children }: { cellContentsElement: any; children: any }) => { + const rowIndex = children?.props?.visibleRowIndex; + const row = data[rowIndex]; + if (!row) return
; + // if resultsField for some reason is not available then use ml + const mlResultsField = resultsField ?? DEFAULT_RESULTS_FIELD; + const parsedFIArray = row[mlResultsField].feature_importance; + let predictedValue: string | number | undefined; + let topClasses: TopClasses = []; + if ( + predictionFieldName !== undefined && + row && + row[mlResultsField][predictionFieldName] !== undefined + ) { + predictedValue = row[mlResultsField][predictionFieldName]; + topClasses = row[mlResultsField].top_classes; + } + + return ( + + ); + }, + } + : undefined; + }, [baseline, data]); + useEffect(() => { if (invalidSortingColumnns.length > 0) { invalidSortingColumnns.forEach((columnId) => { @@ -225,6 +272,7 @@ export const DataGrid: FC = memo( } : {}), }} + popoverContents={popOverContent} pagination={{ ...pagination, pageSizeOptions: [5, 10, 25], diff --git a/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_chart.tsx b/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_chart.tsx new file mode 100644 index 000000000000..b546ac1db57d --- /dev/null +++ b/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_chart.tsx @@ -0,0 +1,166 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + AnnotationDomainTypes, + Axis, + AxisStyle, + Chart, + LineAnnotation, + LineAnnotationStyle, + LineAnnotationDatum, + LineSeries, + PartialTheme, + Position, + RecursivePartial, + ScaleType, + Settings, +} from '@elastic/charts'; +import { EuiIcon } from '@elastic/eui'; + +import React, { useCallback, useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import euiVars from '@elastic/eui/dist/eui_theme_light.json'; +import { DecisionPathPlotData } from './use_classification_path_data'; + +const { euiColorFullShade, euiColorMediumShade } = euiVars; +const axisColor = euiColorMediumShade; + +const baselineStyle: LineAnnotationStyle = { + line: { + strokeWidth: 1, + stroke: euiColorFullShade, + opacity: 0.75, + }, + details: { + fontFamily: 'Arial', + fontSize: 10, + fontStyle: 'bold', + fill: euiColorMediumShade, + padding: 0, + }, +}; + +const axes: RecursivePartial = { + axisLine: { + stroke: axisColor, + }, + tickLabel: { + fontSize: 10, + fill: axisColor, + }, + tickLine: { + stroke: axisColor, + }, + gridLine: { + horizontal: { + dash: [1, 2], + }, + vertical: { + strokeWidth: 0, + }, + }, +}; +const theme: PartialTheme = { + axes, +}; + +interface DecisionPathChartProps { + decisionPathData: DecisionPathPlotData; + predictionFieldName?: string; + baseline?: number; + minDomain: number | undefined; + maxDomain: number | undefined; +} + +const DECISION_PATH_MARGIN = 125; +const DECISION_PATH_ROW_HEIGHT = 10; +const NUM_PRECISION = 3; +const AnnotationBaselineMarker = ; + +export const DecisionPathChart = ({ + decisionPathData, + predictionFieldName, + minDomain, + maxDomain, + baseline, +}: DecisionPathChartProps) => { + // adjust the height so it's compact for items with more features + const baselineData: LineAnnotationDatum[] = useMemo( + () => [ + { + dataValue: baseline, + header: baseline ? baseline.toPrecision(NUM_PRECISION) : '', + details: i18n.translate( + 'xpack.ml.dataframe.analytics.explorationResults.decisionPathBaselineText', + { + defaultMessage: + 'baseline (average of predictions for all data points in the training data set)', + } + ), + }, + ], + [baseline] + ); + // guarantee up to num_precision significant digits + // without having it in scientific notation + const tickFormatter = useCallback((d) => Number(d.toPrecision(NUM_PRECISION)).toString(), []); + + return ( + + + {baseline && ( + + )} + + + + + + ); +}; diff --git a/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_classification.tsx b/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_classification.tsx new file mode 100644 index 000000000000..bd001fa81a58 --- /dev/null +++ b/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_classification.tsx @@ -0,0 +1,105 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC, useMemo, useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiHealth, EuiSpacer, EuiSuperSelect, EuiTitle } from '@elastic/eui'; +import d3 from 'd3'; +import { + isDecisionPathData, + useDecisionPathData, + getStringBasedClassName, +} from './use_classification_path_data'; +import { FeatureImportance, TopClasses } from '../../../../../common/types/feature_importance'; +import { DecisionPathChart } from './decision_path_chart'; +import { MissingDecisionPathCallout } from './missing_decision_path_callout'; + +interface ClassificationDecisionPathProps { + predictedValue: string | boolean; + predictionFieldName?: string; + featureImportance: FeatureImportance[]; + topClasses: TopClasses; +} + +export const ClassificationDecisionPath: FC = ({ + featureImportance, + predictedValue, + topClasses, + predictionFieldName, +}) => { + const [currentClass, setCurrentClass] = useState( + getStringBasedClassName(topClasses[0].class_name) + ); + const { decisionPathData } = useDecisionPathData({ + featureImportance, + predictedValue: currentClass, + }); + const options = useMemo(() => { + const predictionValueStr = getStringBasedClassName(predictedValue); + + return Array.isArray(topClasses) + ? topClasses.map((c) => { + const className = getStringBasedClassName(c.class_name); + return { + value: className, + inputDisplay: + className === predictionValueStr ? ( + + {className} + + ) : ( + className + ), + }; + }) + : undefined; + }, [topClasses, predictedValue]); + + const domain = useMemo(() => { + let maxDomain; + let minDomain; + // if decisionPathData has calculated cumulative path + if (decisionPathData && isDecisionPathData(decisionPathData)) { + const [min, max] = d3.extent(decisionPathData, (d: [string, number, number]) => d[2]); + const buffer = Math.abs(max - min) * 0.1; + maxDomain = max + buffer; + minDomain = min - buffer; + } + return { maxDomain, minDomain }; + }, [decisionPathData]); + + if (!decisionPathData) return ; + + return ( + <> + + + + {i18n.translate( + 'xpack.ml.dataframe.analytics.explorationResults.classificationDecisionPathClassNameTitle', + { + defaultMessage: 'Class name', + } + )} + + + {options !== undefined && ( + + )} + + + ); +}; diff --git a/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_json_viewer.tsx b/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_json_viewer.tsx new file mode 100644 index 000000000000..343324b27f9b --- /dev/null +++ b/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_json_viewer.tsx @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC } from 'react'; +import { EuiCodeBlock } from '@elastic/eui'; +import { FeatureImportance } from '../../../../../common/types/feature_importance'; + +interface DecisionPathJSONViewerProps { + featureImportance: FeatureImportance[]; +} +export const DecisionPathJSONViewer: FC = ({ featureImportance }) => { + return {JSON.stringify(featureImportance)}; +}; diff --git a/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_popover.tsx b/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_popover.tsx new file mode 100644 index 000000000000..263337f93e9a --- /dev/null +++ b/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_popover.tsx @@ -0,0 +1,134 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC, useState } from 'react'; +import { EuiLink, EuiTab, EuiTabs, EuiText } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { RegressionDecisionPath } from './decision_path_regression'; +import { DecisionPathJSONViewer } from './decision_path_json_viewer'; +import { FeatureImportance, TopClasses } from '../../../../../common/types/feature_importance'; +import { ANALYSIS_CONFIG_TYPE } from '../../../data_frame_analytics/common'; +import { ClassificationDecisionPath } from './decision_path_classification'; +import { useMlKibana } from '../../../contexts/kibana'; + +interface DecisionPathPopoverProps { + featureImportance: FeatureImportance[]; + analysisType: ANALYSIS_CONFIG_TYPE; + predictionFieldName?: string; + baseline?: number; + predictedValue?: number | string | undefined; + topClasses?: TopClasses; +} + +enum DECISION_PATH_TABS { + CHART = 'decision_path_chart', + JSON = 'decision_path_json', +} + +export interface ExtendedFeatureImportance extends FeatureImportance { + absImportance?: number; +} + +export const DecisionPathPopover: FC = ({ + baseline, + featureImportance, + predictedValue, + topClasses, + analysisType, + predictionFieldName, +}) => { + const [selectedTabId, setSelectedTabId] = useState(DECISION_PATH_TABS.CHART); + const { + services: { docLinks }, + } = useMlKibana(); + const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = docLinks; + + if (featureImportance.length < 2) { + return ; + } + + const tabs = [ + { + id: DECISION_PATH_TABS.CHART, + name: ( + + ), + }, + { + id: DECISION_PATH_TABS.JSON, + name: ( + + ), + }, + ]; + + return ( + <> +
+ + {tabs.map((tab) => ( + setSelectedTabId(tab.id)} + key={tab.id} + > + {tab.name} + + ))} + +
+ {selectedTabId === DECISION_PATH_TABS.CHART && ( + <> + + + + + ), + }} + /> + + {analysisType === ANALYSIS_CONFIG_TYPE.CLASSIFICATION && ( + + )} + {analysisType === ANALYSIS_CONFIG_TYPE.REGRESSION && ( + + )} + + )} + {selectedTabId === DECISION_PATH_TABS.JSON && ( + + )} + + ); +}; diff --git a/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_regression.tsx b/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_regression.tsx new file mode 100644 index 000000000000..345269a944f0 --- /dev/null +++ b/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/decision_path_regression.tsx @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { FC, useMemo } from 'react'; +import { EuiCallOut } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import d3 from 'd3'; +import { FeatureImportance, TopClasses } from '../../../../../common/types/feature_importance'; +import { useDecisionPathData, isDecisionPathData } from './use_classification_path_data'; +import { DecisionPathChart } from './decision_path_chart'; +import { MissingDecisionPathCallout } from './missing_decision_path_callout'; + +interface RegressionDecisionPathProps { + predictionFieldName?: string; + baseline?: number; + predictedValue?: number | undefined; + featureImportance: FeatureImportance[]; + topClasses?: TopClasses; +} + +export const RegressionDecisionPath: FC = ({ + baseline, + featureImportance, + predictedValue, + predictionFieldName, +}) => { + const { decisionPathData } = useDecisionPathData({ + baseline, + featureImportance, + predictedValue, + }); + const domain = useMemo(() => { + let maxDomain; + let minDomain; + // if decisionPathData has calculated cumulative path + if (decisionPathData && isDecisionPathData(decisionPathData)) { + const [min, max] = d3.extent(decisionPathData, (d: [string, number, number]) => d[2]); + maxDomain = max; + minDomain = min; + const buffer = Math.abs(maxDomain - minDomain) * 0.1; + maxDomain = + (typeof baseline === 'number' ? Math.max(maxDomain, baseline) : maxDomain) + buffer; + minDomain = + (typeof baseline === 'number' ? Math.min(minDomain, baseline) : minDomain) - buffer; + } + return { maxDomain, minDomain }; + }, [decisionPathData, baseline]); + + if (!decisionPathData) return ; + + return ( + <> + {baseline === undefined && ( + + } + color="warning" + iconType="alert" + /> + )} + + + ); +}; diff --git a/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/missing_decision_path_callout.tsx b/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/missing_decision_path_callout.tsx new file mode 100644 index 000000000000..66eb2047b131 --- /dev/null +++ b/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/missing_decision_path_callout.tsx @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { EuiCallOut } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; + +export const MissingDecisionPathCallout = () => { + return ( + + + + ); +}; diff --git a/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/use_classification_path_data.tsx b/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/use_classification_path_data.tsx new file mode 100644 index 000000000000..90216c4a58ff --- /dev/null +++ b/x-pack/plugins/ml/public/application/components/data_grid/feature_importance/use_classification_path_data.tsx @@ -0,0 +1,173 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FeatureImportance, TopClasses } from '../../../../../common/types/feature_importance'; +import { ExtendedFeatureImportance } from './decision_path_popover'; + +export type DecisionPathPlotData = Array<[string, number, number]>; + +interface UseDecisionPathDataParams { + featureImportance: FeatureImportance[]; + baseline?: number; + predictedValue?: string | number | undefined; + topClasses?: TopClasses; +} + +interface RegressionDecisionPathProps { + baseline?: number; + predictedValue?: number | undefined; + featureImportance: FeatureImportance[]; + topClasses?: TopClasses; +} +const FEATURE_NAME = 'feature_name'; +const FEATURE_IMPORTANCE = 'importance'; + +export const isDecisionPathData = (decisionPathData: any): boolean => { + return ( + Array.isArray(decisionPathData) && + decisionPathData.length > 0 && + decisionPathData[0].length === 3 + ); +}; + +// cast to 'True' | 'False' | value to match Eui display +export const getStringBasedClassName = (v: string | boolean | undefined | number): string => { + if (v === undefined) { + return ''; + } + if (typeof v === 'boolean') { + return v ? 'True' : 'False'; + } + if (typeof v === 'number') { + return v.toString(); + } + return v; +}; + +export const useDecisionPathData = ({ + baseline, + featureImportance, + predictedValue, +}: UseDecisionPathDataParams): { decisionPathData: DecisionPathPlotData | undefined } => { + const decisionPathData = useMemo(() => { + return baseline + ? buildRegressionDecisionPathData({ + baseline, + featureImportance, + predictedValue: predictedValue as number | undefined, + }) + : buildClassificationDecisionPathData({ + featureImportance, + currentClass: predictedValue as string | undefined, + }); + }, [baseline, featureImportance, predictedValue]); + + return { decisionPathData }; +}; + +export const buildDecisionPathData = (featureImportance: ExtendedFeatureImportance[]) => { + const finalResult: DecisionPathPlotData = featureImportance + // sort so absolute importance so it goes from bottom (baseline) to top + .sort( + (a: ExtendedFeatureImportance, b: ExtendedFeatureImportance) => + b.absImportance! - a.absImportance! + ) + .map((d) => [d[FEATURE_NAME] as string, d[FEATURE_IMPORTANCE] as number, NaN]); + + // start at the baseline and end at predicted value + // for regression, cumulativeSum should add up to baseline + let cumulativeSum = 0; + for (let i = featureImportance.length - 1; i >= 0; i--) { + cumulativeSum += finalResult[i][1]; + finalResult[i][2] = cumulativeSum; + } + return finalResult; +}; +export const buildRegressionDecisionPathData = ({ + baseline, + featureImportance, + predictedValue, +}: RegressionDecisionPathProps): DecisionPathPlotData | undefined => { + let mappedFeatureImportance: ExtendedFeatureImportance[] = featureImportance; + mappedFeatureImportance = mappedFeatureImportance.map((d) => ({ + ...d, + absImportance: Math.abs(d[FEATURE_IMPORTANCE] as number), + })); + + if (baseline && predictedValue !== undefined && Number.isFinite(predictedValue)) { + // get the adjusted importance needed for when # of fields included in c++ analysis != max allowed + // if num fields included = num features allowed exactly, adjustedImportance should be 0 + const adjustedImportance = + predictedValue - + mappedFeatureImportance.reduce( + (accumulator, currentValue) => accumulator + currentValue.importance!, + 0 + ) - + baseline; + + mappedFeatureImportance.push({ + [FEATURE_NAME]: i18n.translate( + 'xpack.ml.dataframe.analytics.decisionPathFeatureBaselineTitle', + { + defaultMessage: 'baseline', + } + ), + [FEATURE_IMPORTANCE]: baseline, + absImportance: -1, + }); + + // if the difference is small enough then no need to plot the residual feature importance + if (Math.abs(adjustedImportance) > 1e-5) { + mappedFeatureImportance.push({ + [FEATURE_NAME]: i18n.translate( + 'xpack.ml.dataframe.analytics.decisionPathFeatureOtherTitle', + { + defaultMessage: 'other', + } + ), + [FEATURE_IMPORTANCE]: adjustedImportance, + absImportance: 0, // arbitrary importance so this will be of higher importance than baseline + }); + } + } + const filteredFeatureImportance = mappedFeatureImportance.filter( + (f) => f !== undefined + ) as ExtendedFeatureImportance[]; + + return buildDecisionPathData(filteredFeatureImportance); +}; + +export const buildClassificationDecisionPathData = ({ + featureImportance, + currentClass, +}: { + featureImportance: FeatureImportance[]; + currentClass: string | undefined; +}): DecisionPathPlotData | undefined => { + if (currentClass === undefined) return []; + const mappedFeatureImportance: Array< + ExtendedFeatureImportance | undefined + > = featureImportance.map((feature) => { + const classFeatureImportance = Array.isArray(feature.classes) + ? feature.classes.find((c) => getStringBasedClassName(c.class_name) === currentClass) + : feature; + if (classFeatureImportance && typeof classFeatureImportance[FEATURE_IMPORTANCE] === 'number') { + return { + [FEATURE_NAME]: feature[FEATURE_NAME], + [FEATURE_IMPORTANCE]: classFeatureImportance[FEATURE_IMPORTANCE], + absImportance: Math.abs(classFeatureImportance[FEATURE_IMPORTANCE] as number), + }; + } + return undefined; + }); + const filteredFeatureImportance = mappedFeatureImportance.filter( + (f) => f !== undefined + ) as ExtendedFeatureImportance[]; + + return buildDecisionPathData(filteredFeatureImportance); +}; diff --git a/x-pack/plugins/ml/public/application/components/data_grid/types.ts b/x-pack/plugins/ml/public/application/components/data_grid/types.ts index 756f74c8f930..f9ee8c37fabf 100644 --- a/x-pack/plugins/ml/public/application/components/data_grid/types.ts +++ b/x-pack/plugins/ml/public/application/components/data_grid/types.ts @@ -74,6 +74,9 @@ export interface UseIndexDataReturnType | 'tableItems' | 'toggleChartVisibility' | 'visibleColumns' + | 'baseline' + | 'predictionFieldName' + | 'resultsField' > { renderCellValue: RenderCellValue; } @@ -105,4 +108,7 @@ export interface UseDataGridReturnType { tableItems: DataGridItem[]; toggleChartVisibility: () => void; visibleColumns: ColumnId[]; + baseline?: number; + predictionFieldName?: string; + resultsField?: string; } diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/common/analytics.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/common/analytics.ts index 8ad861e616b7..97098ea9e75c 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/common/analytics.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/common/analytics.ts @@ -15,18 +15,19 @@ import { SavedSearchQuery } from '../../contexts/ml'; import { AnalysisConfig, ClassificationAnalysis, - OutlierAnalysis, RegressionAnalysis, + ANALYSIS_CONFIG_TYPE, } from '../../../../common/types/data_frame_analytics'; - +import { + isOutlierAnalysis, + isRegressionAnalysis, + isClassificationAnalysis, + getPredictionFieldName, + getDependentVar, + getPredictedFieldName, +} from '../../../../common/util/analytics_utils'; export type IndexPattern = string; -export enum ANALYSIS_CONFIG_TYPE { - OUTLIER_DETECTION = 'outlier_detection', - REGRESSION = 'regression', - CLASSIFICATION = 'classification', -} - export enum ANALYSIS_ADVANCED_FIELDS { ETA = 'eta', FEATURE_BAG_FRACTION = 'feature_bag_fraction', @@ -156,23 +157,6 @@ export const getAnalysisType = (analysis: AnalysisConfig): string => { return 'unknown'; }; -export const getDependentVar = ( - analysis: AnalysisConfig -): - | RegressionAnalysis['regression']['dependent_variable'] - | ClassificationAnalysis['classification']['dependent_variable'] => { - let depVar = ''; - - if (isRegressionAnalysis(analysis)) { - depVar = analysis.regression.dependent_variable; - } - - if (isClassificationAnalysis(analysis)) { - depVar = analysis.classification.dependent_variable; - } - return depVar; -}; - export const getTrainingPercent = ( analysis: AnalysisConfig ): @@ -190,24 +174,6 @@ export const getTrainingPercent = ( return trainingPercent; }; -export const getPredictionFieldName = ( - analysis: AnalysisConfig -): - | RegressionAnalysis['regression']['prediction_field_name'] - | ClassificationAnalysis['classification']['prediction_field_name'] => { - // If undefined will be defaulted to dependent_variable when config is created - let predictionFieldName; - if (isRegressionAnalysis(analysis) && analysis.regression.prediction_field_name !== undefined) { - predictionFieldName = analysis.regression.prediction_field_name; - } else if ( - isClassificationAnalysis(analysis) && - analysis.classification.prediction_field_name !== undefined - ) { - predictionFieldName = analysis.classification.prediction_field_name; - } - return predictionFieldName; -}; - export const getNumTopClasses = ( analysis: AnalysisConfig ): ClassificationAnalysis['classification']['num_top_classes'] => { @@ -238,35 +204,6 @@ export const getNumTopFeatureImportanceValues = ( return numTopFeatureImportanceValues; }; -export const getPredictedFieldName = ( - resultsField: string, - analysis: AnalysisConfig, - forSort?: boolean -) => { - // default is 'ml' - const predictionFieldName = getPredictionFieldName(analysis); - const defaultPredictionField = `${getDependentVar(analysis)}_prediction`; - const predictedField = `${resultsField}.${ - predictionFieldName ? predictionFieldName : defaultPredictionField - }`; - return predictedField; -}; - -export const isOutlierAnalysis = (arg: any): arg is OutlierAnalysis => { - const keys = Object.keys(arg); - return keys.length === 1 && keys[0] === ANALYSIS_CONFIG_TYPE.OUTLIER_DETECTION; -}; - -export const isRegressionAnalysis = (arg: any): arg is RegressionAnalysis => { - const keys = Object.keys(arg); - return keys.length === 1 && keys[0] === ANALYSIS_CONFIG_TYPE.REGRESSION; -}; - -export const isClassificationAnalysis = (arg: any): arg is ClassificationAnalysis => { - const keys = Object.keys(arg); - return keys.length === 1 && keys[0] === ANALYSIS_CONFIG_TYPE.CLASSIFICATION; -}; - export const isResultsSearchBoolQuery = (arg: any): arg is ResultsSearchBoolQuery => { if (arg === undefined) return false; const keys = Object.keys(arg); @@ -607,3 +544,13 @@ export const loadDocsCount = async ({ }; } }; + +export { + isOutlierAnalysis, + isRegressionAnalysis, + isClassificationAnalysis, + getPredictionFieldName, + ANALYSIS_CONFIG_TYPE, + getDependentVar, + getPredictedFieldName, +}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/common/constants.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/common/constants.ts index 2f14dfdfdfca..c2295a92af89 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/common/constants.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/common/constants.ts @@ -3,8 +3,6 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - -export const DEFAULT_RESULTS_FIELD = 'ml'; export const FEATURE_IMPORTANCE = 'feature_importance'; export const FEATURE_INFLUENCE = 'feature_influence'; export const TOP_CLASSES = 'top_classes'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/common/fields.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/common/fields.ts index 847aefefbc6c..f9c9bf26a9d1 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/common/fields.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/common/fields.ts @@ -4,17 +4,16 @@ * you may not use this file except in compliance with the Elastic License. */ +import { getNumTopClasses, getNumTopFeatureImportanceValues } from './analytics'; +import { Field } from '../../../../common/types/fields'; import { - getNumTopClasses, - getNumTopFeatureImportanceValues, getPredictedFieldName, getDependentVar, getPredictionFieldName, isClassificationAnalysis, isOutlierAnalysis, isRegressionAnalysis, -} from './analytics'; -import { Field } from '../../../../common/types/fields'; +} from '../../../../common/util/analytics_utils'; import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '../../../../../../../src/plugins/data/public'; import { newJobCapsService } from '../../services/new_job_capabilities_service'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_form.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_form.tsx index 25baff98556a..dd9ecc963840 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_form.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/configuration_step/configuration_step_form.tsx @@ -209,7 +209,6 @@ export const ConfigurationStepForm: FC = ({ let unsupportedFieldsErrorMessage; if ( jobType === ANALYSIS_CONFIG_TYPE.CLASSIFICATION && - errorMessage.includes('status_exception') && (errorMessage.includes('must have at most') || errorMessage.includes('must have at least')) ) { maxDistinctValuesErrorMessage = errorMessage; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx index ccac9a697210..2e3a5d89367c 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/classification_exploration/classification_exploration.tsx @@ -9,7 +9,6 @@ import React, { FC } from 'react'; import { i18n } from '@kbn/i18n'; import { ExplorationPageWrapper } from '../exploration_page_wrapper'; - import { EvaluatePanel } from './evaluate_panel'; interface Props { diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx index 34ff36c59fa6..84b44ef0d349 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_page_wrapper/exploration_page_wrapper.tsx @@ -51,7 +51,6 @@ export const ExplorationPageWrapper: FC = ({ jobId, title, EvaluatePanel /> ); } - return ( <> {isLoadingJobConfig === true && jobConfig === undefined && } diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/exploration_results_table.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/exploration_results_table.tsx index 8395a11bd6fd..eea579ef1d06 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/exploration_results_table.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/exploration_results_table.tsx @@ -28,6 +28,8 @@ import { INDEX_STATUS, SEARCH_SIZE, defaultSearchQuery, + getAnalysisType, + ANALYSIS_CONFIG_TYPE, } from '../../../../common'; import { getTaskStateBadge } from '../../../analytics_management/components/analytics_list/use_columns'; import { DATA_FRAME_TASK_STATE } from '../../../analytics_management/components/analytics_list/common'; @@ -36,6 +38,7 @@ import { ExplorationQueryBar } from '../exploration_query_bar'; import { IndexPatternPrompt } from '../index_pattern_prompt'; import { useExplorationResults } from './use_exploration_results'; +import { useMlKibana } from '../../../../../contexts/kibana'; const showingDocs = i18n.translate( 'xpack.ml.dataframe.analytics.explorationResults.documentsShownHelpText', @@ -70,18 +73,27 @@ export const ExplorationResultsTable: FC = React.memo( setEvaluateSearchQuery, title, }) => { + const { + services: { + mlServices: { mlApiServices }, + }, + } = useMlKibana(); const [searchQuery, setSearchQuery] = useState(defaultSearchQuery); useEffect(() => { setEvaluateSearchQuery(searchQuery); }, [JSON.stringify(searchQuery)]); + const analysisType = getAnalysisType(jobConfig.analysis); + const classificationData = useExplorationResults( indexPattern, jobConfig, searchQuery, - getToastNotifications() + getToastNotifications(), + mlApiServices ); + const docFieldsCount = classificationData.columnsWithCharts.length; const { columnsWithCharts, @@ -94,7 +106,6 @@ export const ExplorationResultsTable: FC = React.memo( if (jobConfig === undefined || classificationData === undefined) { return null; } - // if it's a searchBar syntax error leave the table visible so they can try again if (status === INDEX_STATUS.ERROR && !errorMessage.includes('failed to create query')) { return ( @@ -184,6 +195,7 @@ export const ExplorationResultsTable: FC = React.memo( {...classificationData} dataTestSubj="mlExplorationDataGrid" toastNotifications={getToastNotifications()} + analysisType={(analysisType as unknown) as ANALYSIS_CONFIG_TYPE} /> diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/use_exploration_results.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/use_exploration_results.ts index 8d53214d23d4..a56345017258 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/use_exploration_results.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/exploration_results_table/use_exploration_results.ts @@ -4,12 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { useEffect, useMemo } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { EuiDataGridColumn } from '@elastic/eui'; import { CoreSetup } from 'src/core/public'; +import { i18n } from '@kbn/i18n'; +import { MlApiServices } from '../../../../../services/ml_api_service'; import { IndexPattern } from '../../../../../../../../../../src/plugins/data/public'; import { DataLoader } from '../../../../../datavisualizer/index_based/data_loader'; @@ -23,21 +25,26 @@ import { UseIndexDataReturnType, } from '../../../../../components/data_grid'; import { SavedSearchQuery } from '../../../../../contexts/ml'; - import { getIndexData, getIndexFields, DataFrameAnalyticsConfig } from '../../../../common'; import { - DEFAULT_RESULTS_FIELD, - FEATURE_IMPORTANCE, - TOP_CLASSES, -} from '../../../../common/constants'; + getPredictionFieldName, + getDefaultPredictionFieldName, +} from '../../../../../../../common/util/analytics_utils'; +import { FEATURE_IMPORTANCE, TOP_CLASSES } from '../../../../common/constants'; +import { DEFAULT_RESULTS_FIELD } from '../../../../../../../common/constants/data_frame_analytics'; import { sortExplorationResultsFields, ML__ID_COPY } from '../../../../common/fields'; +import { isRegressionAnalysis } from '../../../../common/analytics'; +import { extractErrorMessage } from '../../../../../../../common/util/errors'; export const useExplorationResults = ( indexPattern: IndexPattern | undefined, jobConfig: DataFrameAnalyticsConfig | undefined, searchQuery: SavedSearchQuery, - toastNotifications: CoreSetup['notifications']['toasts'] + toastNotifications: CoreSetup['notifications']['toasts'], + mlApiServices: MlApiServices ): UseIndexDataReturnType => { + const [baseline, setBaseLine] = useState(); + const needsDestIndexFields = indexPattern !== undefined && indexPattern.title === jobConfig?.source.index[0]; @@ -52,7 +59,6 @@ export const useExplorationResults = ( ) ); } - const dataGrid = useDataGrid( columns, 25, @@ -107,16 +113,60 @@ export const useExplorationResults = ( jobConfig?.dest.index, JSON.stringify([searchQuery, dataGrid.visibleColumns]), ]); + const predictionFieldName = useMemo(() => { + if (jobConfig) { + return ( + getPredictionFieldName(jobConfig.analysis) ?? + getDefaultPredictionFieldName(jobConfig.analysis) + ); + } + return undefined; + }, [jobConfig]); + + const getAnalyticsBaseline = useCallback(async () => { + try { + if ( + jobConfig !== undefined && + jobConfig.analysis !== undefined && + isRegressionAnalysis(jobConfig.analysis) + ) { + const result = await mlApiServices.dataFrameAnalytics.getAnalyticsBaseline(jobConfig.id); + if (result?.baseline) { + setBaseLine(result.baseline); + } + } + } catch (e) { + const error = extractErrorMessage(e); + + toastNotifications.addDanger({ + title: i18n.translate( + 'xpack.ml.dataframe.analytics.explorationResults.baselineErrorMessageToast', + { + defaultMessage: 'An error occurred getting feature importance baseline', + } + ), + text: error, + }); + } + }, [mlApiServices, jobConfig]); + + useEffect(() => { + getAnalyticsBaseline(); + }, [jobConfig]); + const resultsField = jobConfig?.dest.results_field ?? DEFAULT_RESULTS_FIELD; const renderCellValue = useRenderCellValue( indexPattern, dataGrid.pagination, dataGrid.tableItems, - jobConfig?.dest.results_field ?? DEFAULT_RESULTS_FIELD + resultsField ); return { ...dataGrid, renderCellValue, + baseline, + predictionFieldName, + resultsField, }; }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/use_outlier_data.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/use_outlier_data.ts index 24649ae5f1e7..151e5ea4e6fe 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/use_outlier_data.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_exploration/components/outlier_exploration/use_outlier_data.ts @@ -29,7 +29,8 @@ import { SavedSearchQuery } from '../../../../../contexts/ml'; import { getToastNotifications } from '../../../../../util/dependency_cache'; import { getIndexData, getIndexFields, DataFrameAnalyticsConfig } from '../../../../common'; -import { DEFAULT_RESULTS_FIELD, FEATURE_INFLUENCE } from '../../../../common/constants'; +import { FEATURE_INFLUENCE } from '../../../../common/constants'; +import { DEFAULT_RESULTS_FIELD } from '../../../../../../../common/constants/data_frame_analytics'; import { sortExplorationResultsFields, ML__ID_COPY } from '../../../../common/fields'; import { getFeatureCount, getOutlierScoreFieldName } from './common'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx index 60c699ba0d37..ce24892c9de4 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/action_clone/clone_action_name.tsx @@ -12,7 +12,7 @@ import { IIndexPattern } from 'src/plugins/data/common'; import { DeepReadonly } from '../../../../../../../common/types/common'; import { DataFrameAnalyticsConfig, isOutlierAnalysis } from '../../../../common'; import { isClassificationAnalysis, isRegressionAnalysis } from '../../../../common/analytics'; -import { DEFAULT_RESULTS_FIELD } from '../../../../common/constants'; +import { DEFAULT_RESULTS_FIELD } from '../../../../../../../common/constants/data_frame_analytics'; import { useMlKibana, useNavigateToPath } from '../../../../../contexts/kibana'; import { DEFAULT_NUM_TOP_FEATURE_IMPORTANCE_VALUES } from '../../hooks/use_create_analytics_form'; import { State } from '../../hooks/use_create_analytics_form/state'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx index 6d73340cc396..0c3bff58c25c 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/analytics_list.tsx @@ -99,13 +99,7 @@ export const DataFrameAnalyticsList: FC = ({ const [isInitialized, setIsInitialized] = useState(false); const [isSourceIndexModalVisible, setIsSourceIndexModalVisible] = useState(false); const [isLoading, setIsLoading] = useState(false); - const [filteredAnalytics, setFilteredAnalytics] = useState<{ - active: boolean; - items: DataFrameAnalyticsListRow[]; - }>({ - active: false, - items: [], - }); + const [filteredAnalytics, setFilteredAnalytics] = useState([]); const [searchQueryText, setSearchQueryText] = useState(''); const [analytics, setAnalytics] = useState([]); const [analyticsStats, setAnalyticsStats] = useState( @@ -129,12 +123,12 @@ export const DataFrameAnalyticsList: FC = ({ blockRefresh ); - const setQueryClauses = (queryClauses: any) => { + const updateFilteredItems = (queryClauses: any) => { if (queryClauses.length) { const filtered = filterAnalytics(analytics, queryClauses); - setFilteredAnalytics({ active: true, items: filtered }); + setFilteredAnalytics(filtered); } else { - setFilteredAnalytics({ active: false, items: [] }); + setFilteredAnalytics(analytics); } }; @@ -146,9 +140,9 @@ export const DataFrameAnalyticsList: FC = ({ if (query && query.ast !== undefined && query.ast.clauses !== undefined) { clauses = query.ast.clauses; } - setQueryClauses(clauses); + updateFilteredItems(clauses); } else { - setQueryClauses([]); + updateFilteredItems([]); } }; @@ -192,9 +186,9 @@ export const DataFrameAnalyticsList: FC = ({ isMlEnabledInSpace ); - const { onTableChange, pageOfItems, pagination, sorting } = useTableSettings( - filteredAnalytics.active ? filteredAnalytics.items : analytics - ); + const { onTableChange, pageOfItems, pagination, sorting } = useTableSettings< + DataFrameAnalyticsListRow + >(DataFrameAnalyticsListColumn.id, filteredAnalytics); // Before the analytics have been loaded for the first time, display the loading indicator only. // Otherwise a user would see 'No data frame analytics found' during the initial loading. diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings.ts index 57eb9f685705..052068c30b84 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/use_table_settings.ts @@ -8,7 +8,6 @@ import { useState } from 'react'; import { Direction, EuiBasicTableProps, EuiTableSortingType } from '@elastic/eui'; import sortBy from 'lodash/sortBy'; import get from 'lodash/get'; -import { DataFrameAnalyticsListColumn, DataFrameAnalyticsListRow } from './common'; const PAGE_SIZE = 10; const PAGE_SIZE_OPTIONS = [10, 25, 50]; @@ -19,37 +18,59 @@ const jobPropertyMap = { Type: 'job_type', }; -interface AnalyticsBasicTableSettings { +// Copying from EUI EuiBasicTable types as type is not correctly picked up for table's onChange +// Can be removed when https://github.com/elastic/eui/issues/4011 is addressed in EUI +export interface Criteria { + page?: { + index: number; + size: number; + }; + sort?: { + field: keyof T; + direction: Direction; + }; +} +export interface CriteriaWithPagination extends Criteria { + page: { + index: number; + size: number; + }; +} + +interface AnalyticsBasicTableSettings { pageIndex: number; pageSize: number; totalItemCount: number; hidePerPageOptions: boolean; - sortField: string; + sortField: keyof T; sortDirection: Direction; } -interface UseTableSettingsReturnValue { - onTableChange: EuiBasicTableProps['onChange']; - pageOfItems: DataFrameAnalyticsListRow[]; - pagination: EuiBasicTableProps['pagination']; +interface UseTableSettingsReturnValue { + onTableChange: EuiBasicTableProps['onChange']; + pageOfItems: T[]; + pagination: EuiBasicTableProps['pagination']; sorting: EuiTableSortingType; } -export function useTableSettings(items: DataFrameAnalyticsListRow[]): UseTableSettingsReturnValue { - const [tableSettings, setTableSettings] = useState({ +export function useTableSettings( + sortByField: keyof TypeOfItem, + items: TypeOfItem[] +): UseTableSettingsReturnValue { + const [tableSettings, setTableSettings] = useState>({ pageIndex: 0, pageSize: PAGE_SIZE, totalItemCount: 0, hidePerPageOptions: false, - sortField: DataFrameAnalyticsListColumn.id, + sortField: sortByField, sortDirection: 'asc', }); const getPageOfItems = ( - list: any[], + list: TypeOfItem[], index: number, size: number, - sortField: string, + sortField: keyof TypeOfItem, sortDirection: Direction ) => { list = sortBy(list, (item) => @@ -72,13 +93,10 @@ export function useTableSettings(items: DataFrameAnalyticsListRow[]): UseTableSe }; }; - const onTableChange = ({ + const onTableChange: EuiBasicTableProps['onChange'] = ({ page = { index: 0, size: PAGE_SIZE }, - sort = { field: DataFrameAnalyticsListColumn.id, direction: 'asc' }, - }: { - page?: { index: number; size: number }; - sort?: { field: string; direction: Direction }; - }) => { + sort = { field: sortByField, direction: 'asc' }, + }: CriteriaWithPagination) => { const { index, size } = page; const { field, direction } = sort; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/analytics_search_bar.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/analytics_search_bar.tsx index 44a6572a3766..7a366bb63420 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/analytics_search_bar.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/analytics_search_bar.tsx @@ -20,6 +20,68 @@ import { Value, DataFrameAnalyticsListRow, } from '../analytics_list/common'; +import { ModelItem } from '../models_management/models_list'; + +export function filterAnalyticsModels( + items: ModelItem[], + clauses: Array +) { + if (clauses.length === 0) { + return items; + } + + // keep count of the number of matches we make as we're looping over the clauses + // we only want to return items which match all clauses, i.e. each search term is ANDed + const matches: Record = items.reduce((p: Record, c) => { + p[c.model_id] = { + model: c, + count: 0, + }; + return p; + }, {}); + + clauses.forEach((c) => { + // the search term could be negated with a minus, e.g. -bananas + const bool = c.match === 'must'; + let ms = []; + + if (c.type === 'term') { + // filter term based clauses, e.g. bananas + // match on model_id and type + // if the term has been negated, AND the matches + if (bool === true) { + ms = items.filter( + (item) => + stringMatch(item.model_id, c.value) === bool || stringMatch(item.type, c.value) === bool + ); + } else { + ms = items.filter( + (item) => + stringMatch(item.model_id, c.value) === bool && stringMatch(item.type, c.value) === bool + ); + } + } else { + // filter other clauses, i.e. the filters for type + if (Array.isArray(c.value)) { + // type value is an array of string(s) e.g. c.value => ['classification'] + ms = items.filter((item) => { + return item.type !== undefined && (c.value as Value[]).includes(item.type); + }); + } else { + ms = items.filter((item) => item[c.field as keyof typeof item] === c.value); + } + } + + ms.forEach((j) => matches[j.model_id].count++); + }); + + // loop through the matches and return only those items which have match all the clauses + const filtered = Object.values(matches) + .filter((m) => (m && m.count) >= clauses.length) + .map((m) => m.model); + + return filtered; +} export function filterAnalytics( items: DataFrameAnalyticsListRow[], diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/index.ts b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/index.ts index 3b901f5063eb..2748764d7f46 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/index.ts +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_search_bar/index.ts @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { AnalyticsSearchBar, filterAnalytics } from './analytics_search_bar'; +export { AnalyticsSearchBar, filterAnalytics, filterAnalyticsModels } from './analytics_search_bar'; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/models_list.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/models_list.tsx index 3104ec55c3a6..338b6444671a 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/models_list.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/models_management/models_list.tsx @@ -4,20 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { FC, useState, useCallback, useMemo } from 'react'; +import React, { FC, useState, useCallback, useEffect, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { - Direction, + EuiBasicTable, EuiFlexGroup, EuiFlexItem, - EuiInMemoryTable, EuiTitle, EuiButton, - EuiSearchBarProps, + EuiSearchBar, EuiSpacer, EuiButtonIcon, EuiBadge, + SearchFilterConfig, } from '@elastic/eui'; // @ts-ignore import { formatDate } from '@elastic/eui/lib/services/format'; @@ -42,6 +42,8 @@ import { refreshAnalyticsList$, useRefreshAnalyticsList, } from '../../../../common'; +import { useTableSettings } from '../analytics_list/use_table_settings'; +import { filterAnalyticsModels, AnalyticsSearchBar } from '../analytics_search_bar'; type Stats = Omit; @@ -66,22 +68,41 @@ export const ModelsList: FC = () => { const { toasts } = useNotifications(); const [searchQueryText, setSearchQueryText] = useState(''); - - const [pageIndex, setPageIndex] = useState(0); - const [pageSize, setPageSize] = useState(10); - const [sortField, setSortField] = useState(ModelsTableToConfigMapping.id); - const [sortDirection, setSortDirection] = useState('asc'); - + const [filteredModels, setFilteredModels] = useState([]); const [isLoading, setIsLoading] = useState(false); const [items, setItems] = useState([]); const [selectedModels, setSelectedModels] = useState([]); - const [modelsToDelete, setModelsToDelete] = useState([]); - const [itemIdToExpandedRowMap, setItemIdToExpandedRowMap] = useState>( {} ); + const updateFilteredItems = (queryClauses: any) => { + if (queryClauses.length) { + const filtered = filterAnalyticsModels(items, queryClauses); + setFilteredModels(filtered); + } else { + setFilteredModels(items); + } + }; + + const filterList = () => { + if (searchQueryText !== '') { + const query = EuiSearchBar.Query.parse(searchQueryText); + let clauses: any = []; + if (query && query.ast !== undefined && query.ast.clauses !== undefined) { + clauses = query.ast.clauses; + } + updateFilteredItems(clauses); + } else { + updateFilteredItems([]); + } + }; + + useEffect(() => { + filterList(); + }, [searchQueryText, items]); + /** * Fetches inference trained models. */ @@ -355,91 +376,51 @@ export const ModelsList: FC = () => { }, ]; - const pagination = { - initialPageIndex: pageIndex, - initialPageSize: pageSize, - totalItemCount: items.length, - pageSizeOptions: [10, 20, 50], - hidePerPageOptions: false, - }; + const filters: SearchFilterConfig[] = + inferenceTypesOptions && inferenceTypesOptions.length > 0 + ? [ + { + type: 'field_value_selection', + field: 'type', + name: i18n.translate('xpack.ml.dataframe.analyticsList.typeFilter', { + defaultMessage: 'Type', + }), + multiSelect: 'or', + options: inferenceTypesOptions, + }, + ] + : []; - const sorting = { - sort: { - field: sortField, - direction: sortDirection, - }, - }; - const search: EuiSearchBarProps = { - query: searchQueryText, - onChange: (searchChange) => { - if (searchChange.error !== null) { - return false; - } - setSearchQueryText(searchChange.queryText); - return true; - }, - box: { - incremental: true, - }, - ...(inferenceTypesOptions && inferenceTypesOptions.length > 0 - ? { - filters: [ - { - type: 'field_value_selection', - field: 'type', - name: i18n.translate('xpack.ml.dataframe.analyticsList.typeFilter', { - defaultMessage: 'Type', - }), - multiSelect: 'or', - options: inferenceTypesOptions, - }, - ], - } - : {}), - ...(selectedModels.length > 0 - ? { - toolsLeft: ( - - - -
- -
-
-
- - - - - -
- ), - } - : {}), - }; + const { onTableChange, pageOfItems, pagination, sorting } = useTableSettings( + ModelsTableToConfigMapping.id, + filteredModels + ); - const onTableChange: EuiInMemoryTable['onTableChange'] = ({ - page = { index: 0, size: 10 }, - sort = { field: ModelsTableToConfigMapping.id, direction: 'asc' }, - }) => { - const { index, size } = page; - setPageIndex(index); - setPageSize(size); - - const { field, direction } = sort; - setSortField(field); - setSortDirection(direction); - }; + const toolsLeft = ( + + + + +
+ +
+
+
+ + + + + +
+
+ ); const isSelectionAllowed = canDeleteDataFrameAnalytics; @@ -473,21 +454,31 @@ export const ModelsList: FC = () => {
- + {selectedModels.length > 0 && toolsLeft} + + + + + + columns={columns} hasActions={true} isExpandable={true} - itemIdToExpandedRowMap={itemIdToExpandedRowMap} isSelectable={false} - items={items} + items={pageOfItems} itemId={ModelsTableToConfigMapping.id} + itemIdToExpandedRowMap={itemIdToExpandedRowMap} loading={isLoading} - onTableChange={onTableChange} - pagination={pagination} - sorting={sorting} - search={search} + onChange={onTableChange} selection={selection} + pagination={pagination!} + sorting={sorting} + data-test-subj={isLoading ? 'mlModelsTable loading' : 'mlModelsTable loaded'} rowProps={(item) => ({ 'data-test-subj': `mlModelsTableRow row-${item.model_id}`, })} diff --git a/x-pack/plugins/ml/public/application/datavisualizer/index_based/data_loader/data_loader.ts b/x-pack/plugins/ml/public/application/datavisualizer/index_based/data_loader/data_loader.ts index 34f86ffa1878..b36eccdde279 100644 --- a/x-pack/plugins/ml/public/application/datavisualizer/index_based/data_loader/data_loader.ts +++ b/x-pack/plugins/ml/public/application/datavisualizer/index_based/data_loader/data_loader.ts @@ -80,7 +80,7 @@ export class DataLoader { earliest: number | undefined, latest: number | undefined, fields: FieldRequestConfig[], - interval?: string + interval?: number ): Promise { const stats = await ml.getVisualizerFieldStats({ indexPatternTitle: this._indexPatternTitle, diff --git a/x-pack/plugins/ml/public/application/datavisualizer/index_based/page.tsx b/x-pack/plugins/ml/public/application/datavisualizer/index_based/page.tsx index 26ed3152058d..bad1488166e2 100644 --- a/x-pack/plugins/ml/public/application/datavisualizer/index_based/page.tsx +++ b/x-pack/plugins/ml/public/application/datavisualizer/index_based/page.tsx @@ -348,7 +348,7 @@ export const Page: FC = () => { earliest, latest, existMetricFields, - aggInterval.expression + aggInterval.asMilliseconds() ); // Add the metric stats to the existing stats in the corresponding config. diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container_service.js b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container_service.js index 712b64af2db8..a6fda86f27a7 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container_service.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container_service.js @@ -111,7 +111,7 @@ export const anomalyDataChange = function ( // Query 1 - load the raw metric data. function getMetricData(config, range) { - const { jobId, detectorIndex, entityFields, interval } = config; + const { jobId, detectorIndex, entityFields, bucketSpanSeconds } = config; const job = mlJobService.getJob(jobId); @@ -122,14 +122,14 @@ export const anomalyDataChange = function ( return mlResultsService .getMetricData( config.datafeedConfig.indices, - config.entityFields, + entityFields, datafeedQuery, config.metricFunction, config.metricFieldName, config.timeField, range.min, range.max, - config.interval + bucketSpanSeconds * 1000 ) .toPromise(); } else { @@ -175,7 +175,14 @@ export const anomalyDataChange = function ( }; return mlResultsService - .getModelPlotOutput(jobId, detectorIndex, criteriaFields, range.min, range.max, interval) + .getModelPlotOutput( + jobId, + detectorIndex, + criteriaFields, + range.min, + range.max, + bucketSpanSeconds * 1000 + ) .toPromise() .then((resp) => { // Return data in format required by the explorer charts. @@ -218,7 +225,7 @@ export const anomalyDataChange = function ( [config.jobId], range.min, range.max, - config.interval, + config.bucketSpanSeconds * 1000, 1, MAX_SCHEDULED_EVENTS ) @@ -252,7 +259,7 @@ export const anomalyDataChange = function ( config.timeField, range.min, range.max, - config.interval + config.bucketSpanSeconds * 1000 ); } diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/common/results_loader/results_loader.ts b/x-pack/plugins/ml/public/application/jobs/new_job/common/results_loader/results_loader.ts index 2b250b962228..af31df863ab7 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/common/results_loader/results_loader.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/common/results_loader/results_loader.ts @@ -161,7 +161,7 @@ export class ResultsLoader { [], this._lastModelTimeStamp, this._jobCreator.end, - `${this._chartInterval.getInterval().asMilliseconds()}ms`, + this._chartInterval.getInterval().asMilliseconds(), agg.mlModelPlotAgg ) .toPromise(); @@ -211,7 +211,7 @@ export class ResultsLoader { [this._jobCreator.jobId], this._jobCreator.start, this._jobCreator.end, - `${this._chartInterval.getInterval().asMilliseconds()}ms`, + this._chartInterval.getInterval().asMilliseconds(), 1 ); @@ -233,7 +233,7 @@ export class ResultsLoader { this._jobCreator.jobId, this._jobCreator.start, this._jobCreator.end, - `${this._chartInterval.getInterval().asMilliseconds()}ms`, + this._chartInterval.getInterval().asMilliseconds(), this._detectorSplitFieldFilters ); diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/common/results_loader/searches.ts b/x-pack/plugins/ml/public/application/jobs/new_job/common/results_loader/searches.ts index 51c396518c85..02a6f47bed6c 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/common/results_loader/searches.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/common/results_loader/searches.ts @@ -32,7 +32,7 @@ export function getScoresByRecord( jobId: string, earliestMs: number, latestMs: number, - interval: string, + intervalMs: number, firstSplitField: SplitFieldWithValue | null ): Promise { return new Promise((resolve, reject) => { @@ -104,7 +104,7 @@ export function getScoresByRecord( byTime: { date_histogram: { field: 'timestamp', - interval, + fixed_interval: `${intervalMs}ms`, min_doc_count: 1, extended_bounds: { min: earliestMs, diff --git a/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts b/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts index 2bdb758be874..3ee50a475900 100644 --- a/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts +++ b/x-pack/plugins/ml/public/application/services/anomaly_timeline_service.ts @@ -180,7 +180,7 @@ export class AnomalyTimelineService { // Pass the interval in seconds as the swim lane relies on a fixed number of seconds between buckets // which wouldn't be the case if e.g. '1M' was used. - const interval = `${swimlaneBucketInterval.asSeconds()}s`; + const intervalMs = swimlaneBucketInterval.asMilliseconds(); let response; if (viewBySwimlaneFieldName === VIEW_BY_JOB_LABEL) { @@ -190,7 +190,7 @@ export class AnomalyTimelineService { jobIds, searchBounds.min.valueOf(), searchBounds.max.valueOf(), - interval, + intervalMs, perPage, fromPage ); @@ -201,7 +201,7 @@ export class AnomalyTimelineService { fieldValues, searchBounds.min.valueOf(), searchBounds.max.valueOf(), - interval, + intervalMs, swimlaneLimit, perPage, fromPage, @@ -269,7 +269,7 @@ export class AnomalyTimelineService { selectedJobIds, earliestMs, latestMs, - this.getSwimlaneBucketInterval(selectedJobs, swimlaneContainerWidth).asSeconds() + 's', + this.getSwimlaneBucketInterval(selectedJobs, swimlaneContainerWidth).asMilliseconds(), swimlaneLimit ); return Object.keys(resp.results); diff --git a/x-pack/plugins/ml/public/application/services/forecast_service.d.ts b/x-pack/plugins/ml/public/application/services/forecast_service.d.ts index 9eff86c753da..e30790c57966 100644 --- a/x-pack/plugins/ml/public/application/services/forecast_service.d.ts +++ b/x-pack/plugins/ml/public/application/services/forecast_service.d.ts @@ -25,7 +25,7 @@ export const mlForecastService: { entityFields: any[], earliestMs: number, latestMs: number, - interval: string, + intervalMs: number, aggType: any ) => Observable; diff --git a/x-pack/plugins/ml/public/application/services/forecast_service.js b/x-pack/plugins/ml/public/application/services/forecast_service.js index 57e50387a03a..c13e265b4655 100644 --- a/x-pack/plugins/ml/public/application/services/forecast_service.js +++ b/x-pack/plugins/ml/public/application/services/forecast_service.js @@ -153,7 +153,7 @@ function getForecastData( entityFields, earliestMs, latestMs, - interval, + intervalMs, aggType ) { // Extract the partition, by, over fields on which to filter. @@ -257,7 +257,7 @@ function getForecastData( times: { date_histogram: { field: 'timestamp', - interval: interval, + fixed_interval: `${intervalMs}ms`, min_doc_count: 1, }, aggs: { diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/data_frame_analytics.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/data_frame_analytics.ts index 7de39d91047e..434200d0383f 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/data_frame_analytics.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/data_frame_analytics.ts @@ -135,4 +135,10 @@ export const dataFrameAnalytics = { method: 'GET', }); }, + getAnalyticsBaseline(analyticsId: string) { + return http({ + path: `${basePath()}/data_frame/analytics/${analyticsId}/baseline`, + method: 'POST', + }); + }, }; diff --git a/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts b/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts index 184039729f9e..9d7ce4f3df59 100644 --- a/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts +++ b/x-pack/plugins/ml/public/application/services/ml_api_service/index.ts @@ -485,7 +485,7 @@ export function mlApiServicesProvider(httpService: HttpService) { earliest?: number; latest?: number; samplerShardSize?: number; - interval?: string; + interval?: number; fields?: FieldRequestConfig[]; maxExamples?: number; }) { diff --git a/x-pack/plugins/ml/public/application/services/results_service/result_service_rx.ts b/x-pack/plugins/ml/public/application/services/results_service/result_service_rx.ts index 898ca8894cbd..22f878a337f5 100644 --- a/x-pack/plugins/ml/public/application/services/results_service/result_service_rx.ts +++ b/x-pack/plugins/ml/public/application/services/results_service/result_service_rx.ts @@ -70,7 +70,7 @@ export function resultsServiceRxProvider(mlApiServices: MlApiServices) { timeFieldName: string, earliestMs: number, latestMs: number, - interval: string + intervalMs: number ): Observable { // Build the criteria to use in the bool filter part of the request. // Add criteria for the time range, entity fields, @@ -136,7 +136,7 @@ export function resultsServiceRxProvider(mlApiServices: MlApiServices) { byTime: { date_histogram: { field: timeFieldName, - interval, + fixed_interval: `${intervalMs}ms`, min_doc_count: 0, }, }, @@ -202,7 +202,7 @@ export function resultsServiceRxProvider(mlApiServices: MlApiServices) { criteriaFields: any[], earliestMs: number, latestMs: number, - interval: string, + intervalMs: number, aggType?: { min: any; max: any } ): Observable { const obj: ModelPlotOutput = { @@ -291,7 +291,7 @@ export function resultsServiceRxProvider(mlApiServices: MlApiServices) { times: { date_histogram: { field: 'timestamp', - interval, + fixed_interval: `${intervalMs}ms`, min_doc_count: 0, }, aggs: { @@ -446,7 +446,7 @@ export function resultsServiceRxProvider(mlApiServices: MlApiServices) { jobIds: string[] | undefined, earliestMs: number, latestMs: number, - interval: string, + intervalMs: number, maxJobs: number, maxEvents: number ): Observable { @@ -518,7 +518,7 @@ export function resultsServiceRxProvider(mlApiServices: MlApiServices) { times: { date_histogram: { field: 'timestamp', - interval, + fixed_interval: `${intervalMs}ms`, min_doc_count: 1, }, aggs: { diff --git a/x-pack/plugins/ml/public/application/services/results_service/results_service.d.ts b/x-pack/plugins/ml/public/application/services/results_service/results_service.d.ts index b26528b76037..aae0cb51aa81 100644 --- a/x-pack/plugins/ml/public/application/services/results_service/results_service.d.ts +++ b/x-pack/plugins/ml/public/application/services/results_service/results_service.d.ts @@ -13,7 +13,7 @@ export function resultsServiceProvider( jobIds: string[], earliestMs: number, latestMs: number, - interval: string | number, + intervalMs: number, perPage?: number, fromPage?: number ): Promise; @@ -41,7 +41,7 @@ export function resultsServiceProvider( influencerFieldValues: string[], earliestMs: number, latestMs: number, - interval: string, + intervalMs: number, maxResults: number, perPage: number, fromPage: number, @@ -57,8 +57,25 @@ export function resultsServiceProvider( timeFieldName: string, earliestMs: number, latestMs: number, - interval: string | number + intervalMs: number + ): Promise; + getEventDistributionData( + index: string, + splitField: string, + filterField: string, + query: any, + metricFunction: string, // ES aggregation name + metricFieldName: string, + timeFieldName: string, + earliestMs: number, + latestMs: number, + intervalMs: number + ): Promise; + getRecordMaxScoreByTime( + jobId: string, + criteriaFields: any[], + earliestMs: number, + latestMs: number, + intervalMs: number ): Promise; - getEventDistributionData(): Promise; - getRecordMaxScoreByTime(): Promise; }; diff --git a/x-pack/plugins/ml/public/application/services/results_service/results_service.js b/x-pack/plugins/ml/public/application/services/results_service/results_service.js index ef00c9025763..fd48845494df 100644 --- a/x-pack/plugins/ml/public/application/services/results_service/results_service.js +++ b/x-pack/plugins/ml/public/application/services/results_service/results_service.js @@ -28,7 +28,7 @@ export function resultsServiceProvider(mlApiServices) { // Pass an empty array or ['*'] to search over all job IDs. // Returned response contains a results property, with a key for job // which has results for the specified time range. - getScoresByBucket(jobIds, earliestMs, latestMs, interval, perPage = 10, fromPage = 1) { + getScoresByBucket(jobIds, earliestMs, latestMs, intervalMs, perPage = 10, fromPage = 1) { return new Promise((resolve, reject) => { const obj = { success: true, @@ -116,7 +116,7 @@ export function resultsServiceProvider(mlApiServices) { byTime: { date_histogram: { field: 'timestamp', - interval: interval, + fixed_interval: `${intervalMs}ms`, min_doc_count: 1, extended_bounds: { min: earliestMs, @@ -492,7 +492,7 @@ export function resultsServiceProvider(mlApiServices) { influencerFieldValues, earliestMs, latestMs, - interval, + intervalMs, maxResults = ANOMALY_SWIM_LANE_HARD_LIMIT, perPage = SWIM_LANE_DEFAULT_PAGE_SIZE, fromPage = 1, @@ -615,7 +615,7 @@ export function resultsServiceProvider(mlApiServices) { byTime: { date_histogram: { field: 'timestamp', - interval, + fixed_interval: `${intervalMs}ms`, min_doc_count: 1, }, aggs: { @@ -1033,7 +1033,7 @@ export function resultsServiceProvider(mlApiServices) { // Extra query object can be supplied, or pass null if no additional query. // Returned response contains a results property, which is an object // of document counts against time (epoch millis). - getEventRateData(index, query, timeFieldName, earliestMs, latestMs, interval) { + getEventRateData(index, query, timeFieldName, earliestMs, latestMs, intervalMs) { return new Promise((resolve, reject) => { const obj = { success: true, results: {} }; @@ -1074,7 +1074,7 @@ export function resultsServiceProvider(mlApiServices) { eventRate: { date_histogram: { field: timeFieldName, - interval: interval, + fixed_interval: `${intervalMs}ms`, min_doc_count: 0, extended_bounds: { min: earliestMs, @@ -1118,7 +1118,7 @@ export function resultsServiceProvider(mlApiServices) { timeFieldName, earliestMs, latestMs, - interval + intervalMs ) { return new Promise((resolve, reject) => { if (splitField === undefined) { @@ -1187,7 +1187,7 @@ export function resultsServiceProvider(mlApiServices) { byTime: { date_histogram: { field: timeFieldName, - interval: interval, + fixed_interval: `${intervalMs}ms`, min_doc_count: AGGREGATION_MIN_DOC_COUNT, }, aggs: { @@ -1277,7 +1277,7 @@ export function resultsServiceProvider(mlApiServices) { // criteria, time range, and aggregation interval. // criteriaFields parameter must be an array, with each object in the array having 'fieldName' // 'fieldValue' properties. - getRecordMaxScoreByTime(jobId, criteriaFields, earliestMs, latestMs, interval) { + getRecordMaxScoreByTime(jobId, criteriaFields, earliestMs, latestMs, intervalMs) { return new Promise((resolve, reject) => { const obj = { success: true, @@ -1331,7 +1331,7 @@ export function resultsServiceProvider(mlApiServices) { times: { date_histogram: { field: 'timestamp', - interval: interval, + fixed_interval: `${intervalMs}ms`, min_doc_count: 1, }, aggs: { diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseries_search_service.ts b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseries_search_service.ts index d1e959b33e5d..5149fecb0ec2 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseries_search_service.ts +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseries_search_service.ts @@ -29,7 +29,7 @@ function getMetricData( entityFields: EntityField[], earliestMs: number, latestMs: number, - interval: string + intervalMs: number ): Observable { if ( isModelPlotChartableForDetector(job, detectorIndex) && @@ -76,7 +76,7 @@ function getMetricData( criteriaFields, earliestMs, latestMs, - interval + intervalMs ); } else { const obj: ModelPlotOutput = { @@ -96,7 +96,7 @@ function getMetricData( chartConfig.timeField, earliestMs, latestMs, - interval + intervalMs ) .pipe( map((resp) => { diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js index 0e99d64cf202..7d173e161a1c 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js @@ -629,7 +629,7 @@ export class TimeSeriesExplorer extends React.Component { nonBlankEntities, searchBounds.min.valueOf(), searchBounds.max.valueOf(), - stateUpdate.contextAggregationInterval.expression + stateUpdate.contextAggregationInterval.asMilliseconds() ) .toPromise() .then((resp) => { @@ -652,7 +652,7 @@ export class TimeSeriesExplorer extends React.Component { this.getCriteriaFields(detectorIndex, entityControls), searchBounds.min.valueOf(), searchBounds.max.valueOf(), - stateUpdate.contextAggregationInterval.expression + stateUpdate.contextAggregationInterval.asMilliseconds() ) .then((resp) => { const fullRangeRecordScoreData = processRecordScoreResults(resp.results); @@ -703,7 +703,7 @@ export class TimeSeriesExplorer extends React.Component { nonBlankEntities, searchBounds.min.valueOf(), searchBounds.max.valueOf(), - stateUpdate.contextAggregationInterval.expression, + stateUpdate.contextAggregationInterval.asMilliseconds(), aggType ) .toPromise() diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/get_focus_data.ts b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/get_focus_data.ts index 23d1e3f7cc90..ce0d7b0abc3e 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/get_focus_data.ts +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer_utils/get_focus_data.ts @@ -61,7 +61,7 @@ export function getFocusData( nonBlankEntities, searchBounds.min.valueOf(), searchBounds.max.valueOf(), - focusAggregationInterval.expression + focusAggregationInterval.asMilliseconds() ), // Query 2 - load all the records across selected time range for the chart anomaly markers. mlResultsService.getRecordsForCriteria( @@ -77,7 +77,7 @@ export function getFocusData( [selectedJob.job_id], searchBounds.min.valueOf(), searchBounds.max.valueOf(), - focusAggregationInterval.expression, + focusAggregationInterval.asMilliseconds(), 1, MAX_SCHEDULED_EVENTS ), @@ -123,7 +123,7 @@ export function getFocusData( nonBlankEntities, searchBounds.min.valueOf(), searchBounds.max.valueOf(), - focusAggregationInterval.expression, + focusAggregationInterval.asMilliseconds(), aggType ); })() diff --git a/x-pack/plugins/ml/server/models/bucket_span_estimator/polled_data_checker.js b/x-pack/plugins/ml/server/models/bucket_span_estimator/polled_data_checker.js index fd0cab7c0625..981ffe9618d9 100644 --- a/x-pack/plugins/ml/server/models/bucket_span_estimator/polled_data_checker.js +++ b/x-pack/plugins/ml/server/models/bucket_span_estimator/polled_data_checker.js @@ -56,7 +56,7 @@ export function polledDataCheckerFactory({ asCurrentUser }) { date_histogram: { min_doc_count: 1, field: this.timeField, - interval: `${intervalMs}ms`, + fixed_interval: `${intervalMs}ms`, }, }, }, diff --git a/x-pack/plugins/ml/server/models/bucket_span_estimator/single_series_checker.js b/x-pack/plugins/ml/server/models/bucket_span_estimator/single_series_checker.js index 750f0cfc0b4a..5dd0a5ff563d 100644 --- a/x-pack/plugins/ml/server/models/bucket_span_estimator/single_series_checker.js +++ b/x-pack/plugins/ml/server/models/bucket_span_estimator/single_series_checker.js @@ -166,7 +166,7 @@ export function singleSeriesCheckerFactory({ asCurrentUser }) { non_empty_buckets: { date_histogram: { field: this.timeField, - interval: `${intervalMs}ms`, + fixed_interval: `${intervalMs}ms`, }, }, }, diff --git a/x-pack/plugins/ml/server/models/data_frame_analytics/feature_importance.ts b/x-pack/plugins/ml/server/models/data_frame_analytics/feature_importance.ts new file mode 100644 index 000000000000..94f54a565487 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_frame_analytics/feature_importance.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IScopedClusterClient } from 'kibana/server'; +import { + getDefaultPredictionFieldName, + getPredictionFieldName, + isRegressionAnalysis, +} from '../../../common/util/analytics_utils'; +import { DEFAULT_RESULTS_FIELD } from '../../../common/constants/data_frame_analytics'; +// Obtains data for the data frame analytics feature importance functionalities +// such as baseline, decision paths, or importance summary. +export function analyticsFeatureImportanceProvider({ + asInternalUser, + asCurrentUser, +}: IScopedClusterClient) { + async function getRegressionAnalyticsBaseline(analyticsId: string): Promise { + const { body } = await asInternalUser.ml.getDataFrameAnalytics({ + id: analyticsId, + }); + const jobConfig = body.data_frame_analytics[0]; + if (!isRegressionAnalysis) return undefined; + const destinationIndex = jobConfig.dest.index; + const predictionFieldName = getPredictionFieldName(jobConfig.analysis); + const mlResultsField = jobConfig.dest?.results_field ?? DEFAULT_RESULTS_FIELD; + const predictedField = `${mlResultsField}.${ + predictionFieldName ? predictionFieldName : getDefaultPredictionFieldName(jobConfig.analysis) + }`; + const isTrainingField = `${mlResultsField}.is_training`; + + const params = { + index: destinationIndex, + size: 0, + body: { + query: { + bool: { + filter: [ + { + term: { + [isTrainingField]: true, + }, + }, + ], + }, + }, + aggs: { + featureImportanceBaseline: { + avg: { + field: predictedField, + }, + }, + }, + }, + }; + let baseline; + const { body: aggregationResult } = await asCurrentUser.search(params); + if (aggregationResult) { + baseline = aggregationResult.aggregations.featureImportanceBaseline.value; + } + return baseline; + } + + return { + getRegressionAnalyticsBaseline, + }; +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/sample_data_weblogs/ml/datafeed_low_request_rate.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/sample_data_weblogs/ml/datafeed_low_request_rate.json index a9865183320d..084aa0845540 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/sample_data_weblogs/ml/datafeed_low_request_rate.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/sample_data_weblogs/ml/datafeed_low_request_rate.json @@ -10,7 +10,7 @@ "buckets": { "date_histogram": { "field": "timestamp", - "interval": 3600000 + "fixed_interval": "1h" }, "aggregations": { "timestamp": { diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/manifest.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/manifest.json index 1e7fcdd4320f..36d1df6db4c9 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/manifest.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/manifest.json @@ -40,6 +40,46 @@ { "id": "linux_anomalous_user_name_ecs", "file": "linux_anomalous_user_name_ecs.json" + }, + { + "id": "linux_rare_metadata_process", + "file": "linux_rare_metadata_process.json" + }, + { + "id": "linux_rare_metadata_user", + "file": "linux_rare_metadata_user.json" + }, + { + "id": "linux_rare_user_compiler", + "file": "linux_rare_user_compiler.json" + }, + { + "id": "linux_rare_kernel_module_arguments", + "file": "linux_rare_kernel_module_arguments.json" + }, + { + "id": "linux_rare_sudo_user", + "file": "linux_rare_sudo_user.json" + }, + { + "id": "linux_system_user_discovery", + "file": "linux_system_user_discovery.json" + }, + { + "id": "linux_system_information_discovery", + "file": "linux_system_information_discovery.json" + }, + { + "id": "linux_system_process_discovery", + "file": "linux_system_process_discovery.json" + }, + { + "id": "linux_network_connection_discovery", + "file": "linux_network_connection_discovery.json" + }, + { + "id": "linux_network_configuration_discovery", + "file": "linux_network_configuration_discovery.json" } ], "datafeeds": [ @@ -77,6 +117,56 @@ "id": "datafeed-linux_anomalous_user_name_ecs", "file": "datafeed_linux_anomalous_user_name_ecs.json", "job_id": "linux_anomalous_user_name_ecs" + }, + { + "id": "datafeed-linux_rare_metadata_process", + "file": "datafeed_linux_rare_metadata_process.json", + "job_id": "linux_rare_metadata_process" + }, + { + "id": "datafeed-linux_rare_metadata_user", + "file": "datafeed_linux_rare_metadata_user.json", + "job_id": "linux_rare_metadata_user" + }, + { + "id": "datafeed-linux_rare_user_compiler", + "file": "datafeed_linux_rare_user_compiler.json", + "job_id": "linux_rare_user_compiler" + }, + { + "id": "datafeed-linux_rare_kernel_module_arguments", + "file": "datafeed_linux_rare_kernel_module_arguments.json", + "job_id": "linux_rare_kernel_module_arguments" + }, + { + "id": "datafeed-linux_rare_sudo_user", + "file": "datafeed_linux_rare_sudo_user.json", + "job_id": "linux_rare_sudo_user" + }, + { + "id": "datafeed-linux_system_information_discovery", + "file": "datafeed_linux_system_information_discovery.json", + "job_id": "linux_system_information_discovery" + }, + { + "id": "datafeed-linux_system_process_discovery", + "file": "datafeed_linux_system_process_discovery.json", + "job_id": "linux_system_process_discovery" + }, + { + "id": "datafeed-linux_system_user_discovery", + "file": "datafeed_linux_system_user_discovery.json", + "job_id": "linux_system_user_discovery" + }, + { + "id": "datafeed-linux_network_configuration_discovery", + "file": "datafeed_linux_network_configuration_discovery.json", + "job_id": "linux_network_configuration_discovery" + }, + { + "id": "datafeed-linux_network_connection_discovery", + "file": "datafeed_linux_network_connection_discovery.json", + "job_id": "linux_network_connection_discovery" } ] } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_network_configuration_discovery.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_network_configuration_discovery.json new file mode 100644 index 000000000000..d4a130770c92 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_network_configuration_discovery.json @@ -0,0 +1,26 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "max_empty_searches": 10, + "query": { + "bool": { + "must": [ + { + "bool": { + "should": [ + {"term": {"process.name": "arp"}}, + {"term": {"process.name": "echo"}}, + {"term": {"process.name": "ethtool"}}, + {"term": {"process.name": "ifconfig"}}, + {"term": {"process.name": "ip"}}, + {"term": {"process.name": "iptables"}}, + {"term": {"process.name": "ufw"}} + ] + } + } + ] + } + } +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_network_connection_discovery.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_network_connection_discovery.json new file mode 100644 index 000000000000..0ae80df4bd47 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_network_connection_discovery.json @@ -0,0 +1,23 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "max_empty_searches": 10, + "query": { + "bool": { + "must": [ + { + "bool": { + "should": [ + {"term": {"process.name": "netstat"}}, + {"term": {"process.name": "ss"}}, + {"term": {"process.name": "route"}}, + {"term": {"process.name": "showmount"}} + ] + } + } + ] + } + } +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_kernel_module_arguments.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_kernel_module_arguments.json new file mode 100644 index 000000000000..99bb690c8d73 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_kernel_module_arguments.json @@ -0,0 +1,22 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "max_empty_searches": 10, + "query": { + "bool": { + "filter": [{"exists": {"field": "process.title"}}], + "must": [ + {"bool": { + "should": [ + {"term": {"process.name": "insmod"}}, + {"term": {"process.name": "kmod"}}, + {"term": {"process.name": "modprobe"}}, + {"term": {"process.name": "rmod"}} + ] + }} + ] + } + } +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_metadata_process.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_metadata_process.json new file mode 100644 index 000000000000..dc0f6c4e81b3 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_metadata_process.json @@ -0,0 +1,12 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "max_empty_searches": 10, + "query": { + "bool": { + "filter": [{"term": {"destination.ip": "169.254.169.254"}}] + } + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_metadata_user.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_metadata_user.json new file mode 100644 index 000000000000..dc0f6c4e81b3 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_metadata_user.json @@ -0,0 +1,12 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "max_empty_searches": 10, + "query": { + "bool": { + "filter": [{"term": {"destination.ip": "169.254.169.254"}}] + } + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_sudo_user.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_sudo_user.json new file mode 100644 index 000000000000..544675f3d48d --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_sudo_user.json @@ -0,0 +1,15 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "max_empty_searches": 10, + "query": { + "bool": { + "filter": [ + {"term": {"event.action": "executed"}}, + {"term": {"process.name": "sudo"}} + ] + } + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_user_compiler.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_user_compiler.json new file mode 100644 index 000000000000..027b12401000 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_rare_user_compiler.json @@ -0,0 +1,22 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "max_empty_searches": 10, + "query": { + "bool": { + "filter": [{"term": {"event.action": "executed"}}], + "must": [ + {"bool": { + "should": [ + {"term": {"process.name": "compile"}}, + {"term": {"process.name": "gcc"}}, + {"term": {"process.name": "make"}}, + {"term": {"process.name": "yasm"}} + ] + }} + ] + } + } +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_system_information_discovery.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_system_information_discovery.json new file mode 100644 index 000000000000..6e7ce26763f7 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_system_information_discovery.json @@ -0,0 +1,31 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "max_empty_searches": 10, + "query": { + "bool": { + "must": [ + { + "bool": { + "should": [ + {"term": {"process.name": "cat"}}, + {"term": {"process.name": "grep"}}, + {"term": {"process.name": "head"}}, + {"term": {"process.name": "hostname"}}, + {"term": {"process.name": "less"}}, + {"term": {"process.name": "ls"}}, + {"term": {"process.name": "lsmod"}}, + {"term": {"process.name": "more"}}, + {"term": {"process.name": "strings"}}, + {"term": {"process.name": "tail"}}, + {"term": {"process.name": "uptime"}}, + {"term": {"process.name": "uname"}} + ] + } + } + ] + } + } +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_system_process_discovery.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_system_process_discovery.json new file mode 100644 index 000000000000..dbd8f54ff971 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_system_process_discovery.json @@ -0,0 +1,21 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "max_empty_searches": 10, + "query": { + "bool": { + "must": [ + { + "bool": { + "should": [ + {"term": {"process.name": "ps"}}, + {"term": {"process.name": "top"}} + ] + } + } + ] + } + } +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_system_user_discovery.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_system_user_discovery.json new file mode 100644 index 000000000000..24230094a47d --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/datafeed_linux_system_user_discovery.json @@ -0,0 +1,23 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "max_empty_searches": 10, + "query": { + "bool": { + "must": [ + { + "bool": { + "should": [ + {"term": {"process.name": "users"}}, + {"term": {"process.name": "w"}}, + {"term": {"process.name": "who"}}, + {"term": {"process.name": "whoami"}} + ] + } + } + ] + } + } +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_network_configuration_discovery.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_network_configuration_discovery.json new file mode 100644 index 000000000000..6d687764085e --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_network_configuration_discovery.json @@ -0,0 +1,53 @@ +{ + "job_type": "anomaly_detector", + "description": "Security: Auditbeat - Looks for commands related to system network configuration discovery from an unusual user context. This can be due to uncommon troubleshooting activity or due to a compromised account. A compromised account may be used by a threat actor to engage in system network configuration discovery in order to increase their understanding of connected networks and hosts. This information may be used to shape follow-up behaviors such as lateral movement or additional discovery.", + "groups": [ + "security", + "auditbeat", + "process" + ], + "analysis_config": { + "bucket_span": "15m", + "detectors": [ + { + "detector_description": "rare by \"user.name\"", + "function": "rare", + "by_field_name": "user.name" + } + ], + "influencers": [ + "process.name", + "host.name", + "process.args", + "user.name" + ] + }, + "allow_lazy_open": true, + "analysis_limits": { + "model_memory_limit": "64mb" + }, + "data_description": { + "time_field": "@timestamp" + }, + "custom_settings": { + "created_by": "ml-module-siem-auditbeat", + "custom_urls": [ + { + "url_name": "Host Details by process name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Host Details by user name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by process name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by user name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + } + ] + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_network_connection_discovery.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_network_connection_discovery.json new file mode 100644 index 000000000000..b41439548dd5 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_network_connection_discovery.json @@ -0,0 +1,53 @@ +{ + "job_type": "anomaly_detector", + "description": "Security: Auditbeat - Looks for commands related to system network connection discovery from an unusual user context. This can be due to uncommon troubleshooting activity or due to a compromised account. A compromised account may be used by a threat actor to engage in system network connection discovery in order to increase their understanding of connected services and systems. This information may be used to shape follow-up behaviors such as lateral movement or additional discovery.", + "groups": [ + "security", + "auditbeat", + "process" + ], + "analysis_config": { + "bucket_span": "15m", + "detectors": [ + { + "detector_description": "rare by \"user.name\"", + "function": "rare", + "by_field_name": "user.name" + } + ], + "influencers": [ + "process.name", + "host.name", + "process.args", + "user.name" + ] + }, + "allow_lazy_open": true, + "analysis_limits": { + "model_memory_limit": "64mb" + }, + "data_description": { + "time_field": "@timestamp" + }, + "custom_settings": { + "created_by": "ml-module-siem-auditbeat", + "custom_urls": [ + { + "url_name": "Host Details by process name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Host Details by user name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by process name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by user name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + } + ] + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_kernel_module_arguments.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_kernel_module_arguments.json new file mode 100644 index 000000000000..1b79e8305425 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_kernel_module_arguments.json @@ -0,0 +1,45 @@ +{ + "job_type": "anomaly_detector", + "description": "Security: Auditbeat - Looks for unusual kernel modules which are often used for stealth.", + "groups": [ + "security", + "auditbeat", + "process" + ], + "analysis_config": { + "bucket_span": "15m", + "detectors": [ + { + "detector_description": "rare by \"process.title\"", + "function": "rare", + "by_field_name": "process.title" + } + ], + "influencers": [ + "process.title", + "process.working_directory", + "host.name", + "user.name" + ] + }, + "allow_lazy_open": true, + "analysis_limits": { + "model_memory_limit": "32mb" + }, + "data_description": { + "time_field": "@timestamp" + }, + "custom_settings": { + "created_by": "ml-module-siem-auditbeat", + "custom_urls": [ + { + "url_name": "Host Details by user name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by user name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + } + ] + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_metadata_process.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_metadata_process.json new file mode 100644 index 000000000000..7295f11e600d --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_metadata_process.json @@ -0,0 +1,52 @@ +{ + "job_type": "anomaly_detector", + "description": "Security: Auditbeat - Looks for anomalous access to the metadata service by an unusual process. The metadata service may be targeted in order to harvest credentials or user data scripts containing secrets.", + "groups": [ + "security", + "auditbeat", + "process" + ], + "analysis_config": { + "bucket_span": "15m", + "detectors": [ + { + "detector_description": "rare by \"process.name\"", + "function": "rare", + "by_field_name": "process.name" + } + ], + "influencers": [ + "host.name", + "user.name", + "process.name" + ] + }, + "allow_lazy_open": true, + "analysis_limits": { + "model_memory_limit": "32mb" + }, + "data_description": { + "time_field": "@timestamp" + }, + "custom_settings": { + "created_by": "ml-module-siem-auditbeat", + "custom_urls": [ + { + "url_name": "Host Details by process name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Host Details by user name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by process name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by user name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + } + ] + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_metadata_user.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_metadata_user.json new file mode 100644 index 000000000000..049d10920de0 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_metadata_user.json @@ -0,0 +1,43 @@ +{ + "job_type": "anomaly_detector", + "description": "Security: Auditbeat - Looks for anomalous access to the metadata service by an unusual user. The metadata service may be targeted in order to harvest credentials or user data scripts containing secrets.", + "groups": [ + "security", + "auditbeat", + "process" + ], + "analysis_config": { + "bucket_span": "15m", + "detectors": [ + { + "detector_description": "rare by \"user.name\"", + "function": "rare", + "by_field_name": "user.name" + } + ], + "influencers": [ + "host.name", + "user.name" + ] + }, + "allow_lazy_open": true, + "analysis_limits": { + "model_memory_limit": "32mb" + }, + "data_description": { + "time_field": "@timestamp" + }, + "custom_settings": { + "created_by": "ml-module-siem-auditbeat", + "custom_urls": [ + { + "url_name": "Host Details by user name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by user name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + } + ] + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_sudo_user.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_sudo_user.json new file mode 100644 index 000000000000..654f5c76e569 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_sudo_user.json @@ -0,0 +1,53 @@ +{ + "job_type": "anomaly_detector", + "description": "Security: Auditbeat - Looks for sudo activity from an unusual user context.", + "groups": [ + "security", + "auditbeat", + "process" + ], + "analysis_config": { + "bucket_span": "15m", + "detectors": [ + { + "detector_description": "rare by \"user.name\"", + "function": "rare", + "by_field_name": "user.name" + } + ], + "influencers": [ + "process.name", + "host.name", + "process.args", + "user.name" + ] + }, + "allow_lazy_open": true, + "analysis_limits": { + "model_memory_limit": "32mb" + }, + "data_description": { + "time_field": "@timestamp" + }, + "custom_settings": { + "created_by": "ml-module-siem-auditbeat", + "custom_urls": [ + { + "url_name": "Host Details by process name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Host Details by user name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by process name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by user name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + } + ] + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_user_compiler.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_user_compiler.json new file mode 100644 index 000000000000..245b7e0819c7 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_rare_user_compiler.json @@ -0,0 +1,45 @@ +{ + "job_type": "anomaly_detector", + "description": "Security: Auditbeat - Looks for compiler activity by a user context which does not normally run compilers. This can be ad-hoc software changes or unauthorized software deployment. This can also be due to local privliege elevation via locally run exploits or malware activity.", + "groups": [ + "security", + "auditbeat", + "process" + ], + "analysis_config": { + "bucket_span": "15m", + "detectors": [ + { + "detector_description": "rare by \"user.name\"", + "function": "rare", + "by_field_name": "user.name" + } + ], + "influencers": [ + "process.title", + "host.name", + "process.working_directory", + "user.name" + ] + }, + "allow_lazy_open": true, + "analysis_limits": { + "model_memory_limit": "256mb" + }, + "data_description": { + "time_field": "@timestamp" + }, + "custom_settings": { + "created_by": "ml-module-siem-auditbeat", + "custom_urls": [ + { + "url_name": "Host Details by user name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by user name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + } + ] + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_system_information_discovery.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_system_information_discovery.json new file mode 100644 index 000000000000..3a51223b4899 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_system_information_discovery.json @@ -0,0 +1,53 @@ +{ + "job_type": "anomaly_detector", + "description": "Security: Auditbeat - Looks for commands related to system information discovery from an unusual user context. This can be due to uncommon troubleshooting activity or due to a compromised account. A compromised account may be used to engage in system information discovery in order to gather detailed information about system configuration and software versions. This may be a precursor to selection of a persistence mechanism or a method of privilege elevation.", + "groups": [ + "security", + "auditbeat", + "process" + ], + "analysis_config": { + "bucket_span": "15m", + "detectors": [ + { + "detector_description": "rare by \"user.name\"", + "function": "rare", + "by_field_name": "user.name" + } + ], + "influencers": [ + "process.name", + "host.name", + "process.args", + "user.name" + ] + }, + "allow_lazy_open": true, + "analysis_limits": { + "model_memory_limit": "16mb" + }, + "data_description": { + "time_field": "@timestamp" + }, + "custom_settings": { + "created_by": "ml-module-siem-auditbeat", + "custom_urls": [ + { + "url_name": "Host Details by process name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Host Details by user name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by process name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by user name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + } + ] + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_system_process_discovery.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_system_process_discovery.json new file mode 100644 index 000000000000..592bb5a717fc --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_system_process_discovery.json @@ -0,0 +1,53 @@ +{ + "job_type": "anomaly_detector", + "description": "Security: Auditbeat - Looks for commands related to system process discovery from an unusual user context. This can be due to uncommon troubleshooting activity or due to a compromised account. A compromised account may be used to engage in system process discovery in order to increase their understanding of software applications running on a target host or network. This may be a precursor to selection of a persistence mechanism or a method of privilege elevation.", + "groups": [ + "security", + "auditbeat", + "process" + ], + "analysis_config": { + "bucket_span": "15m", + "detectors": [ + { + "detector_description": "rare by \"user.name\"", + "function": "rare", + "by_field_name": "user.name" + } + ], + "influencers": [ + "process.name", + "host.name", + "process.args", + "user.name" + ] + }, + "allow_lazy_open": true, + "analysis_limits": { + "model_memory_limit": "16mb" + }, + "data_description": { + "time_field": "@timestamp" + }, + "custom_settings": { + "created_by": "ml-module-siem-auditbeat", + "custom_urls": [ + { + "url_name": "Host Details by process name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Host Details by user name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by process name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by user name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + } + ] + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_system_user_discovery.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_system_user_discovery.json new file mode 100644 index 000000000000..33f42c274b33 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_auditbeat/ml/linux_system_user_discovery.json @@ -0,0 +1,53 @@ +{ + "job_type": "anomaly_detector", + "description": "Security: Auditbeat - Looks for commands related to system user or owner discovery from an unusual user context. This can be due to uncommon troubleshooting activity or due to a compromised account. A compromised account may be used to engage in system owner or user discovery in order to identify currently active or primary users of a system. This may be a precursor to additional discovery, credential dumping or privilege elevation activity.", + "groups": [ + "security", + "auditbeat", + "process" + ], + "analysis_config": { + "bucket_span": "15m", + "detectors": [ + { + "detector_description": "rare by \"user.name\"", + "function": "rare", + "by_field_name": "user.name" + } + ], + "influencers": [ + "process.name", + "host.name", + "process.args", + "user.name" + ] + }, + "allow_lazy_open": true, + "analysis_limits": { + "model_memory_limit": "16mb" + }, + "data_description": { + "time_field": "@timestamp" + }, + "custom_settings": { + "created_by": "ml-module-siem-auditbeat", + "custom_urls": [ + { + "url_name": "Host Details by process name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Host Details by user name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by process name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by user name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + } + ] + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/manifest.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/manifest.json index ffbf5aa7d8bb..969873ead6d9 100644 --- a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/manifest.json +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/manifest.json @@ -48,6 +48,14 @@ { "id": "windows_rare_user_runas_event", "file": "windows_rare_user_runas_event.json" + }, + { + "id": "windows_rare_metadata_process", + "file": "windows_rare_metadata_process.json" + }, + { + "id": "windows_rare_metadata_user", + "file": "windows_rare_metadata_user.json" } ], "datafeeds": [ @@ -95,6 +103,16 @@ "id": "datafeed-windows_rare_user_runas_event", "file": "datafeed_windows_rare_user_runas_event.json", "job_id": "windows_rare_user_runas_event" + }, + { + "id": "datafeed-windows_rare_metadata_process", + "file": "datafeed_windows_rare_metadata_process.json", + "job_id": "windows_rare_metadata_process" + }, + { + "id": "datafeed-windows_rare_metadata_user", + "file": "datafeed_windows_rare_metadata_user.json", + "job_id": "windows_rare_metadata_user" } ] -} +} \ No newline at end of file diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/ml/datafeed_windows_rare_metadata_process.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/ml/datafeed_windows_rare_metadata_process.json new file mode 100644 index 000000000000..dc0f6c4e81b3 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/ml/datafeed_windows_rare_metadata_process.json @@ -0,0 +1,12 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "max_empty_searches": 10, + "query": { + "bool": { + "filter": [{"term": {"destination.ip": "169.254.169.254"}}] + } + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/ml/datafeed_windows_rare_metadata_user.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/ml/datafeed_windows_rare_metadata_user.json new file mode 100644 index 000000000000..dc0f6c4e81b3 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/ml/datafeed_windows_rare_metadata_user.json @@ -0,0 +1,12 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "max_empty_searches": 10, + "query": { + "bool": { + "filter": [{"term": {"destination.ip": "169.254.169.254"}}] + } + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/ml/windows_rare_metadata_process.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/ml/windows_rare_metadata_process.json new file mode 100644 index 000000000000..85fddbcc53e0 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/ml/windows_rare_metadata_process.json @@ -0,0 +1,52 @@ +{ + "job_type": "anomaly_detector", + "description": "Security: Winlogbeat - Looks for anomalous access to the metadata service by an unusual process. The metadata service may be targeted in order to harvest credentials or user data scripts containing secrets.", + "groups": [ + "security", + "winlogbeat", + "process" + ], + "analysis_config": { + "bucket_span": "15m", + "detectors": [ + { + "detector_description": "rare by \"process.name\"", + "function": "rare", + "by_field_name": "process.name" + } + ], + "influencers": [ + "process.name", + "host.name", + "user.name" + ] + }, + "allow_lazy_open": true, + "analysis_limits": { + "model_memory_limit": "64mb" + }, + "data_description": { + "time_field": "@timestamp" + }, + "custom_settings": { + "created_by": "ml-module-siem-winlogbeat", + "custom_urls": [ + { + "url_name": "Host Details by process name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Host Details by user name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by process name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'process.name%20:%20%22$process.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by user name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + } + ] + } + } diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/ml/windows_rare_metadata_user.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/ml/windows_rare_metadata_user.json new file mode 100644 index 000000000000..767c2d5b30ad --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/siem_winlogbeat/ml/windows_rare_metadata_user.json @@ -0,0 +1,43 @@ +{ + "job_type": "anomaly_detector", + "description": "Security: Winlogbeat - Looks for anomalous access to the metadata service by an unusual user. The metadata service may be targeted in order to harvest credentials or user data scripts containing secrets.", + "groups": [ + "security", + "winlogbeat", + "process" + ], + "analysis_config": { + "bucket_span": "15m", + "detectors": [ + { + "detector_description": "rare by \"user.name\"", + "function": "rare", + "by_field_name": "user.name" + } + ], + "influencers": [ + "host.name", + "user.name" + ] + }, + "allow_lazy_open": true, + "analysis_limits": { + "model_memory_limit": "32mb" + }, + "data_description": { + "time_field": "@timestamp" + }, + "custom_settings": { + "created_by": "ml-module-siem-winlogbeat", + "custom_urls": [ + { + "url_name": "Host Details by user name", + "url_value": "security/hosts/ml-hosts/$host.name$?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + }, + { + "url_name": "Hosts Overview by user name", + "url_value": "security/hosts/ml-hosts?_g=()&query=(query:'user.name%20:%20%22$user.name$%22',language:kuery)&timerange=(global:(linkTo:!(timeline),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')),timeline:(linkTo:!(global),timerange:(from:'$earliest$',kind:absolute,to:'$latest$')))" + } + ] + } + } diff --git a/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts b/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts index dbfa4b5656e5..95c4e7915005 100644 --- a/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts +++ b/x-pack/plugins/ml/server/models/data_visualizer/data_visualizer.ts @@ -468,7 +468,7 @@ export class DataVisualizer { timeFieldName: string, earliestMs: number, latestMs: number, - interval: number, + intervalMs: number, maxExamples: number ): Promise { // Batch up fields by type, getting stats for multiple fields at a time. @@ -526,7 +526,7 @@ export class DataVisualizer { timeFieldName, earliestMs, latestMs, - interval + intervalMs ); batchStats.push(stats); } @@ -710,7 +710,7 @@ export class DataVisualizer { timeFieldName: string, earliestMs: number, latestMs: number, - interval: number + intervalMs: number ): Promise { const index = indexPatternTitle; const size = 0; @@ -718,11 +718,12 @@ export class DataVisualizer { // Don't use the sampler aggregation as this can lead to some potentially // confusing date histogram results depending on the date range of data amongst shards. + const aggs = { eventRate: { date_histogram: { field: timeFieldName, - interval, + fixed_interval: `${intervalMs}ms`, min_doc_count: 1, }, }, @@ -756,7 +757,7 @@ export class DataVisualizer { return { documentCounts: { - interval, + interval: intervalMs, buckets, }, }; diff --git a/x-pack/plugins/ml/server/models/file_data_visualizer/import_data.ts b/x-pack/plugins/ml/server/models/file_data_visualizer/import_data.ts index 6108454c08aa..26dba7c2f00c 100644 --- a/x-pack/plugins/ml/server/models/file_data_visualizer/import_data.ts +++ b/x-pack/plugins/ml/server/models/file_data_visualizer/import_data.ts @@ -94,7 +94,7 @@ export function importDataProvider({ asCurrentUser }: IScopedClusterClient) { _meta: { created_by: INDEX_META_DATA_CREATED_BY, }, - properties: mappings, + properties: mappings.properties, }, }; diff --git a/x-pack/plugins/ml/server/models/job_service/jobs.ts b/x-pack/plugins/ml/server/models/job_service/jobs.ts index e047d31ba6eb..f4378e29ef82 100644 --- a/x-pack/plugins/ml/server/models/job_service/jobs.ts +++ b/x-pack/plugins/ml/server/models/job_service/jobs.ts @@ -407,28 +407,21 @@ export function jobsProvider(client: IScopedClusterClient) { // Job IDs in supplied array may contain wildcard '*' characters // e.g. *_low_request_rate_ecs async function jobsExist(jobIds: string[] = []) { - // Get the list of job IDs. - const { body } = await asInternalUser.ml.getJobs({ - job_id: jobIds.join(), - }); - const results: { [id: string]: boolean } = {}; - if (body.count > 0) { - const allJobIds = body.jobs.map((job) => job.job_id); - - // Check if each of the supplied IDs match existing jobs. - jobIds.forEach((jobId) => { - // Create a Regex for each supplied ID as wildcard * is allowed. - const regexp = new RegExp(`^${jobId.replace(/\*+/g, '.*')}$`); - const exists = allJobIds.some((existsJobId) => regexp.test(existsJobId)); - results[jobId] = exists; - }); - } else { - jobIds.forEach((jobId) => { + for (const jobId of jobIds) { + try { + const { body } = await asInternalUser.ml.getJobs({ + job_id: jobId, + }); + results[jobId] = body.count > 0; + } catch (e) { + // if a non-wildcarded job id is supplied, the get jobs endpoint will 404 + if (e.body?.status !== 404) { + throw e; + } results[jobId] = false; - }); + } } - return results; } diff --git a/x-pack/plugins/ml/server/models/job_service/new_job/line_chart.ts b/x-pack/plugins/ml/server/models/job_service/new_job/line_chart.ts index 9eea1ea2a28a..128b28a22344 100644 --- a/x-pack/plugins/ml/server/models/job_service/new_job/line_chart.ts +++ b/x-pack/plugins/ml/server/models/job_service/new_job/line_chart.ts @@ -114,7 +114,7 @@ function getSearchJsonFromConfig( times: { date_histogram: { field: timeField, - interval: intervalMs, + fixed_interval: `${intervalMs}ms`, min_doc_count: 0, extended_bounds: { min: start, diff --git a/x-pack/plugins/ml/server/models/job_service/new_job/population_chart.ts b/x-pack/plugins/ml/server/models/job_service/new_job/population_chart.ts index 567afec80940..71e81158d888 100644 --- a/x-pack/plugins/ml/server/models/job_service/new_job/population_chart.ts +++ b/x-pack/plugins/ml/server/models/job_service/new_job/population_chart.ts @@ -142,7 +142,7 @@ function getPopulationSearchJsonFromConfig( times: { date_histogram: { field: timeField, - interval: intervalMs, + fixed_interval: `${intervalMs}ms`, min_doc_count: 0, extended_bounds: { min: start, diff --git a/x-pack/plugins/ml/server/models/job_service/new_job_caps/__mocks__/responses/kibana_saved_objects.json b/x-pack/plugins/ml/server/models/job_service/new_job_caps/__mocks__/responses/kibana_saved_objects.json index ca356b2bede2..9e2af7626423 100644 --- a/x-pack/plugins/ml/server/models/job_service/new_job_caps/__mocks__/responses/kibana_saved_objects.json +++ b/x-pack/plugins/ml/server/models/job_service/new_job_caps/__mocks__/responses/kibana_saved_objects.json @@ -20,7 +20,7 @@ "type": "index-pattern", "id": "be14ceb0-66b1-11e9-91c9-ffa52374d341", "attributes": { - "typeMeta": "{\"params\":{\"rollup_index\":\"cloud_roll_index\"},\"aggs\":{\"histogram\":{\"NetworkOut\":{\"agg\":\"histogram\",\"interval\":5},\"CPUUtilization\":{\"agg\":\"histogram\",\"interval\":5},\"NetworkIn\":{\"agg\":\"histogram\",\"interval\":5}},\"avg\":{\"NetworkOut\":{\"agg\":\"avg\"},\"CPUUtilization\":{\"agg\":\"avg\"},\"NetworkIn\":{\"agg\":\"avg\"},\"DiskReadBytes\":{\"agg\":\"avg\"}},\"min\":{\"NetworkOut\":{\"agg\":\"min\"},\"NetworkIn\":{\"agg\":\"min\"}},\"value_count\":{\"NetworkOut\":{\"agg\":\"value_count\"},\"DiskReadBytes\":{\"agg\":\"value_count\"},\"CPUUtilization\":{\"agg\":\"value_count\"},\"NetworkIn\":{\"agg\":\"value_count\"}},\"max\":{\"CPUUtilization\":{\"agg\":\"max\"},\"DiskReadBytes\":{\"agg\":\"max\"}},\"date_histogram\":{\"@timestamp\":{\"agg\":\"date_histogram\",\"delay\":\"1d\",\"interval\":\"5m\",\"time_zone\":\"UTC\"}},\"terms\":{\"instance\":{\"agg\":\"terms\"},\"sourcetype.keyword\":{\"agg\":\"terms\"},\"region\":{\"agg\":\"terms\"}},\"sum\":{\"DiskReadBytes\":{\"agg\":\"sum\"},\"NetworkOut\":{\"agg\":\"sum\"}}}}", + "typeMeta": "{\"params\":{\"rollup_index\":\"cloud_roll_index\"},\"aggs\":{\"histogram\":{\"NetworkOut\":{\"agg\":\"histogram\",\"interval\":5},\"CPUUtilization\":{\"agg\":\"histogram\",\"interval\":5},\"NetworkIn\":{\"agg\":\"histogram\",\"interval\":5}},\"avg\":{\"NetworkOut\":{\"agg\":\"avg\"},\"CPUUtilization\":{\"agg\":\"avg\"},\"NetworkIn\":{\"agg\":\"avg\"},\"DiskReadBytes\":{\"agg\":\"avg\"}},\"min\":{\"NetworkOut\":{\"agg\":\"min\"},\"NetworkIn\":{\"agg\":\"min\"}},\"value_count\":{\"NetworkOut\":{\"agg\":\"value_count\"},\"DiskReadBytes\":{\"agg\":\"value_count\"},\"CPUUtilization\":{\"agg\":\"value_count\"},\"NetworkIn\":{\"agg\":\"value_count\"}},\"max\":{\"CPUUtilization\":{\"agg\":\"max\"},\"DiskReadBytes\":{\"agg\":\"max\"}},\"date_histogram\":{\"@timestamp\":{\"agg\":\"date_histogram\",\"delay\":\"1d\",\"fixed_interval\":\"5m\",\"time_zone\":\"UTC\"}},\"terms\":{\"instance\":{\"agg\":\"terms\"},\"sourcetype.keyword\":{\"agg\":\"terms\"},\"region\":{\"agg\":\"terms\"}},\"sum\":{\"DiskReadBytes\":{\"agg\":\"sum\"},\"NetworkOut\":{\"agg\":\"sum\"}}}}", "title": "cloud_roll_index", "type": "rollup" }, diff --git a/x-pack/plugins/ml/server/models/job_service/new_job_caps/__mocks__/responses/rollup_caps.json b/x-pack/plugins/ml/server/models/job_service/new_job_caps/__mocks__/responses/rollup_caps.json index 2b2f8576d676..b62bce700413 100644 --- a/x-pack/plugins/ml/server/models/job_service/new_job_caps/__mocks__/responses/rollup_caps.json +++ b/x-pack/plugins/ml/server/models/job_service/new_job_caps/__mocks__/responses/rollup_caps.json @@ -37,7 +37,7 @@ { "agg": "date_histogram", "delay": "1d", - "interval": "5m", + "fixed_interval": "5m", "time_zone": "UTC" } ], @@ -123,7 +123,7 @@ { "agg": "date_histogram", "delay": "1d", - "interval": "5m", + "fixed_interval": "5m", "time_zone": "UTC" } ], @@ -174,7 +174,7 @@ { "agg": "date_histogram", "delay": "1d", - "interval": "5m", + "fixed_interval": "5m", "time_zone": "UTC" } ] diff --git a/x-pack/plugins/ml/server/routes/apidoc.json b/x-pack/plugins/ml/server/routes/apidoc.json index 86a62b28abb5..dab00a03b546 100644 --- a/x-pack/plugins/ml/server/routes/apidoc.json +++ b/x-pack/plugins/ml/server/routes/apidoc.json @@ -20,6 +20,7 @@ "DataVisualizer", "GetOverallStats", "GetStatsForFields", + "GetHistogramsForFields", "AnomalyDetectors", "CreateAnomalyDetectors", diff --git a/x-pack/plugins/ml/server/routes/data_frame_analytics.ts b/x-pack/plugins/ml/server/routes/data_frame_analytics.ts index dea4803e8275..7606420eacef 100644 --- a/x-pack/plugins/ml/server/routes/data_frame_analytics.ts +++ b/x-pack/plugins/ml/server/routes/data_frame_analytics.ts @@ -20,6 +20,7 @@ import { import { IndexPatternHandler } from '../models/data_frame_analytics/index_patterns'; import { DeleteDataFrameAnalyticsWithIndexStatus } from '../../common/types/data_frame_analytics'; import { getAuthorizationHeader } from '../lib/request_authorization'; +import { analyticsFeatureImportanceProvider } from '../models/data_frame_analytics/feature_importance'; function getIndexPatternId(context: RequestHandlerContext, patternName: string) { const iph = new IndexPatternHandler(context.core.savedObjects.client); @@ -545,4 +546,38 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat } }) ); + + /** + * @apiGroup DataFrameAnalytics + * + * @api {get} /api/ml/data_frame/analytics/baseline Get analytics's feature importance baseline + * @apiName GetDataFrameAnalyticsBaseline + * @apiDescription Returns the baseline for data frame analytics job. + * + * @apiSchema (params) analyticsIdSchema + */ + router.post( + { + path: '/api/ml/data_frame/analytics/{analyticsId}/baseline', + validate: { + params: analyticsIdSchema, + }, + options: { + tags: ['access:ml:canGetDataFrameAnalytics'], + }, + }, + mlLicense.fullLicenseAPIGuard(async ({ client, request, response }) => { + try { + const { analyticsId } = request.params; + const { getRegressionAnalyticsBaseline } = analyticsFeatureImportanceProvider(client); + const baseline = await getRegressionAnalyticsBaseline(analyticsId); + + return response.ok({ + body: { baseline }, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); } diff --git a/x-pack/plugins/ml/server/routes/data_visualizer.ts b/x-pack/plugins/ml/server/routes/data_visualizer.ts index a697fe017f19..50d9be1be423 100644 --- a/x-pack/plugins/ml/server/routes/data_visualizer.ts +++ b/x-pack/plugins/ml/server/routes/data_visualizer.ts @@ -84,7 +84,7 @@ export function dataVisualizerRoutes({ router, mlLicense }: RouteInitialization) /** * @apiGroup DataVisualizer * - * @api {post} /api/ml/data_visualizer/get_field_stats/:indexPatternTitle Get histograms for fields + * @api {post} /api/ml/data_visualizer/get_field_histograms/:indexPatternTitle Get histograms for fields * @apiName GetHistogramsForFields * @apiDescription Returns the histograms on a list fields in the specified index pattern. * diff --git a/x-pack/plugins/ml/server/routes/schemas/data_visualizer_schema.ts b/x-pack/plugins/ml/server/routes/schemas/data_visualizer_schema.ts index 24e45514e1ef..57bc5578e92c 100644 --- a/x-pack/plugins/ml/server/routes/schemas/data_visualizer_schema.ts +++ b/x-pack/plugins/ml/server/routes/schemas/data_visualizer_schema.ts @@ -32,8 +32,8 @@ export const dataVisualizerFieldStatsSchema = schema.object({ earliest: schema.maybe(schema.number()), /** Latest timestamp for search, as epoch ms (optional). */ latest: schema.maybe(schema.number()), - /** Aggregation interval to use for obtaining document counts over time (optional). */ - interval: schema.maybe(schema.string()), + /** Aggregation interval, in milliseconds, to use for obtaining document counts over time (optional). */ + interval: schema.maybe(schema.number()), /** Maximum number of examples to return for text type fields. */ maxExamples: schema.number(), }); diff --git a/x-pack/plugins/monitoring/public/alerts/cpu_usage_alert/cpu_usage_alert.tsx b/x-pack/plugins/monitoring/public/alerts/cpu_usage_alert/cpu_usage_alert.tsx index 56cba83813a6..c9f82eb52143 100644 --- a/x-pack/plugins/monitoring/public/alerts/cpu_usage_alert/cpu_usage_alert.tsx +++ b/x-pack/plugins/monitoring/public/alerts/cpu_usage_alert/cpu_usage_alert.tsx @@ -23,6 +23,6 @@ export function createCpuUsageAlertType(): AlertTypeModel { ), validate, defaultActionMessage: '{{context.internalFullMessage}}', - requiresAppContext: false, + requiresAppContext: true, }; } diff --git a/x-pack/plugins/monitoring/public/alerts/legacy_alert/legacy_alert.tsx b/x-pack/plugins/monitoring/public/alerts/legacy_alert/legacy_alert.tsx index 58b37e43085f..f6223d41ab30 100644 --- a/x-pack/plugins/monitoring/public/alerts/legacy_alert/legacy_alert.tsx +++ b/x-pack/plugins/monitoring/public/alerts/legacy_alert/legacy_alert.tsx @@ -33,7 +33,7 @@ export function createLegacyAlertTypes(): AlertTypeModel[] { ), defaultActionMessage: '{{context.internalFullMessage}}', validate: () => ({ errors: {} }), - requiresAppContext: false, + requiresAppContext: true, }; }); } diff --git a/x-pack/plugins/monitoring/server/config.test.ts b/x-pack/plugins/monitoring/server/config.test.ts index 32b8691bd604..2efc325a3ede 100644 --- a/x-pack/plugins/monitoring/server/config.test.ts +++ b/x-pack/plugins/monitoring/server/config.test.ts @@ -86,6 +86,9 @@ describe('config schema', () => { "index": "filebeat-*", }, "max_bucket_size": 10000, + "metricbeat": Object { + "index": "metricbeat-*", + }, "min_interval_seconds": 10, "show_license_expiration": true, }, diff --git a/x-pack/plugins/monitoring/server/config.ts b/x-pack/plugins/monitoring/server/config.ts index 789211c43db3..6ae99e3d16d6 100644 --- a/x-pack/plugins/monitoring/server/config.ts +++ b/x-pack/plugins/monitoring/server/config.ts @@ -29,6 +29,9 @@ export const configSchema = schema.object({ logs: schema.object({ index: schema.string({ defaultValue: 'filebeat-*' }), }), + metricbeat: schema.object({ + index: schema.string({ defaultValue: 'metricbeat-*' }), + }), max_bucket_size: schema.number({ defaultValue: 10000 }), elasticsearch: monitoringElasticsearchConfigSchema, container: schema.object({ diff --git a/x-pack/plugins/monitoring/server/lib/ccs_utils.js b/x-pack/plugins/monitoring/server/lib/ccs_utils.js index dab1e87435c8..bef07124fb43 100644 --- a/x-pack/plugins/monitoring/server/lib/ccs_utils.js +++ b/x-pack/plugins/monitoring/server/lib/ccs_utils.js @@ -5,6 +5,21 @@ */ import { isFunction, get } from 'lodash'; +export function appendMetricbeatIndex(config, indexPattern) { + // Leverage this function to also append the dynamic metricbeat index too + let mbIndex = null; + // TODO: NP + // This function is called with both NP config and LP config + if (isFunction(config.get)) { + mbIndex = config.get('monitoring.ui.metricbeat.index'); + } else { + mbIndex = get(config, 'monitoring.ui.metricbeat.index'); + } + + const newIndexPattern = `${indexPattern},${mbIndex}`; + return newIndexPattern; +} + /** * Prefix all comma separated index patterns within the original {@code indexPattern}. * @@ -27,7 +42,7 @@ export function prefixIndexPattern(config, indexPattern, ccs) { } if (!ccsEnabled || !ccs) { - return indexPattern; + return appendMetricbeatIndex(config, indexPattern); } const patterns = indexPattern.split(','); @@ -35,10 +50,10 @@ export function prefixIndexPattern(config, indexPattern, ccs) { // if a wildcard is used, then we also want to search the local indices if (ccs === '*') { - return `${prefixedPattern},${indexPattern}`; + return appendMetricbeatIndex(config, `${prefixedPattern},${indexPattern}`); } - return prefixedPattern; + return appendMetricbeatIndex(config, prefixedPattern); } /** diff --git a/x-pack/plugins/monitoring/server/lib/create_query.js b/x-pack/plugins/monitoring/server/lib/create_query.js index 04e0d7642ec5..1983dc3dcf9a 100644 --- a/x-pack/plugins/monitoring/server/lib/create_query.js +++ b/x-pack/plugins/monitoring/server/lib/create_query.js @@ -57,7 +57,7 @@ export function createQuery(options) { let typeFilter; if (type) { - typeFilter = { term: { type } }; + typeFilter = { bool: { should: [{ term: { type } }, { term: { 'metricset.name': type } }] } }; } let clusterUuidFilter; diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.js index 6abb392e5881..84384021a359 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.js @@ -17,15 +17,23 @@ export function handleResponse(clusterState, shardStats, nodeUuid) { return (response) => { let nodeSummary = {}; const nodeStatsHits = get(response, 'hits.hits', []); - const nodes = nodeStatsHits.map((hit) => hit._source.source_node); // using [0] value because query results are sorted desc per timestamp + const nodes = nodeStatsHits.map((hit) => + get(hit, '_source.elasticsearch.node', hit._source.source_node) + ); // using [0] value because query results are sorted desc per timestamp const node = nodes[0] || getDefaultNodeFromId(nodeUuid); - const sourceStats = get(response, 'hits.hits[0]._source.node_stats'); + const sourceStats = + get(response, 'hits.hits[0]._source.elasticsearch.node.stats') || + get(response, 'hits.hits[0]._source.node_stats'); const clusterNode = get(clusterState, ['nodes', nodeUuid]); const stats = { resolver: nodeUuid, - node_ids: nodes.map((node) => node.uuid), + node_ids: nodes.map((node) => node.id || node.uuid), attributes: node.attributes, - transport_address: node.transport_address, + transport_address: get( + response, + 'hits.hits[0]._source.service.address', + node.transport_address + ), name: node.name, type: node.type, }; @@ -45,10 +53,17 @@ export function handleResponse(clusterState, shardStats, nodeUuid) { totalShards: _shardStats.shardCount, indexCount: _shardStats.indexCount, documents: get(sourceStats, 'indices.docs.count'), - dataSize: get(sourceStats, 'indices.store.size_in_bytes'), - freeSpace: get(sourceStats, 'fs.total.available_in_bytes'), - totalSpace: get(sourceStats, 'fs.total.total_in_bytes'), - usedHeap: get(sourceStats, 'jvm.mem.heap_used_percent'), + dataSize: + get(sourceStats, 'indices.store.size_in_bytes') || + get(sourceStats, 'indices.store.size.bytes'), + freeSpace: + get(sourceStats, 'fs.total.available_in_bytes') || + get(sourceStats, 'fs.summary.available.bytes'), + totalSpace: + get(sourceStats, 'fs.total.total_in_bytes') || get(sourceStats, 'fs.summary.total.bytes'), + usedHeap: + get(sourceStats, 'jvm.mem.heap_used_percent') || + get(sourceStats, 'jvm.mem.heap.used.pct'), status: i18n.translate('xpack.monitoring.es.nodes.onlineStatusLabel', { defaultMessage: 'Online', }), diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.js index 573f1792e5f8..68bca96e2911 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.js @@ -19,6 +19,7 @@ export async function getNodeIds(req, indexPattern, { clusterUuid }, size) { filterPath: ['aggregations.composite_data.buckets'], body: { query: createQuery({ + type: 'node_stats', start, end, metric: ElasticsearchMetric.getMetricFields(), diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js index 682da324ee72..c2794b7e7fa4 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.js @@ -96,6 +96,7 @@ export async function getNodes(req, esIndexPattern, pageOfNodes, clusterStats, n }, filterPath: [ 'hits.hits._source.source_node', + 'hits.hits._source.elasticsearch.node', 'aggregations.nodes.buckets.key', ...LISTING_METRICS_PATHS, ], diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.js b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.js index 3c719c2ddfbf..317c1cddf57a 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.js +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/map_nodes_info.js @@ -17,25 +17,29 @@ export function mapNodesInfo(nodeHits, clusterStats, nodesShardCount) { const clusterState = get(clusterStats, 'cluster_state', { nodes: {} }); return nodeHits.reduce((prev, node) => { - const sourceNode = get(node, '_source.source_node'); + const sourceNode = get(node, '_source.source_node') || get(node, '_source.elasticsearch.node'); const calculatedNodeType = calculateNodeType(sourceNode, get(clusterState, 'master_node')); const { nodeType, nodeTypeLabel, nodeTypeClass } = getNodeTypeClassLabel( sourceNode, calculatedNodeType ); - const isOnline = !isUndefined(get(clusterState, ['nodes', sourceNode.uuid])); + const isOnline = !isUndefined(get(clusterState, ['nodes', sourceNode.uuid || sourceNode.id])); return { ...prev, - [sourceNode.uuid]: { + [sourceNode.uuid || sourceNode.id]: { name: sourceNode.name, transport_address: sourceNode.transport_address, type: nodeType, isOnline, nodeTypeLabel: nodeTypeLabel, nodeTypeClass: nodeTypeClass, - shardCount: get(nodesShardCount, `nodes[${sourceNode.uuid}].shardCount`, 0), + shardCount: get( + nodesShardCount, + `nodes[${sourceNode.uuid || sourceNode.id}].shardCount`, + 0 + ), }, }; }, {}); diff --git a/x-pack/plugins/reporting/common/constants.ts b/x-pack/plugins/reporting/common/constants.ts index c461c2de4e2a..e5bca43cef56 100644 --- a/x-pack/plugins/reporting/common/constants.ts +++ b/x-pack/plugins/reporting/common/constants.ts @@ -16,6 +16,7 @@ export const API_BASE_URL_V1 = '/api/reporting/v1'; // export const API_BASE_GENERATE_V1 = `${API_BASE_URL_V1}/generate`; export const API_LIST_URL = '/api/reporting/jobs'; export const API_GENERATE_IMMEDIATE = `${API_BASE_URL_V1}/generate/immediate/csv/saved-object`; +export const API_DIAGNOSE_URL = `${API_BASE_URL}/diagnose`; export const CONTENT_TYPE_CSV = 'text/csv'; export const CSV_REPORTING_ACTION = 'downloadCsvReport'; diff --git a/x-pack/plugins/reporting/public/components/report_diagnostic.tsx b/x-pack/plugins/reporting/public/components/report_diagnostic.tsx new file mode 100644 index 000000000000..b5b055207ddb --- /dev/null +++ b/x-pack/plugins/reporting/public/components/report_diagnostic.tsx @@ -0,0 +1,281 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import React, { useState, Fragment } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiButton, + EuiButtonEmpty, + EuiCallOut, + EuiCodeBlock, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiSpacer, + EuiSteps, + EuiText, + EuiTitle, +} from '@elastic/eui'; +import { ReportingAPIClient, DiagnoseResponse } from '../lib/reporting_api_client'; + +interface Props { + apiClient: ReportingAPIClient; +} + +type ResultStatus = 'danger' | 'incomplete' | 'complete'; + +enum statuses { + configStatus = 'configStatus', + chromeStatus = 'chromeStatus', + screenshotStatus = 'screenshotStatus', +} + +interface State { + isFlyoutVisible: boolean; + configStatus: ResultStatus; + chromeStatus: ResultStatus; + screenshotStatus: ResultStatus; + help: string[]; + logs: string; + isBusy: boolean; + success: boolean; +} + +const initialState: State = { + [statuses.configStatus]: 'incomplete', + [statuses.chromeStatus]: 'incomplete', + [statuses.screenshotStatus]: 'incomplete', + isFlyoutVisible: false, + help: [], + logs: '', + isBusy: false, + success: true, +}; + +export const ReportDiagnostic = ({ apiClient }: Props) => { + const [state, setStateBase] = useState(initialState); + const setState = (s: Partial) => + setStateBase({ + ...state, + ...s, + }); + const { + configStatus, + isBusy, + screenshotStatus, + chromeStatus, + isFlyoutVisible, + help, + logs, + success, + } = state; + + const closeFlyout = () => setState({ ...initialState, isFlyoutVisible: false }); + const showFlyout = () => setState({ isFlyoutVisible: true }); + const apiWrapper = (apiMethod: () => Promise, statusProp: statuses) => () => { + setState({ isBusy: true, [statusProp]: 'incomplete' }); + apiMethod() + .then((response) => { + setState({ + isBusy: false, + help: response.help, + logs: response.logs, + success: response.success, + [statusProp]: response.success ? 'complete' : 'danger', + }); + }) + .catch((error) => { + setState({ + isBusy: false, + help: [ + i18n.translate('xpack.reporting.listing.diagnosticApiCallFailure', { + defaultMessage: `There was a problem running the diagnostic: {error}`, + values: { error }, + }), + ], + logs: `${error.message}`, + success: false, + [statusProp]: 'danger', + }); + }); + }; + + const steps = [ + { + title: i18n.translate('xpack.reporting.listing.diagnosticConfigTitle', { + defaultMessage: 'Verify Kibana Configuration', + }), + children: ( + + + + + + + + ), + status: !success && configStatus !== 'complete' ? 'danger' : configStatus, + }, + ]; + + if (configStatus === 'complete') { + steps.push({ + title: i18n.translate('xpack.reporting.listing.diagnosticBrowserTitle', { + defaultMessage: 'Check Browser', + }), + children: ( + + + + + + + + ), + status: !success && chromeStatus !== 'complete' ? 'danger' : chromeStatus, + }); + } + + if (chromeStatus === 'complete') { + steps.push({ + title: i18n.translate('xpack.reporting.listing.diagnosticScreenshotTitle', { + defaultMessage: 'Check Screen Capture Capabilities', + }), + children: ( + + + + + + + + ), + status: !success && screenshotStatus !== 'complete' ? 'danger' : screenshotStatus, + }); + } + + if (screenshotStatus === 'complete') { + steps.push({ + title: i18n.translate('xpack.reporting.listing.diagnosticSuccessTitle', { + defaultMessage: 'All set!', + }), + children: ( + + + + ), + status: !success ? 'danger' : screenshotStatus, + }); + } + + if (!success) { + steps.push({ + title: i18n.translate('xpack.reporting.listing.diagnosticFailureTitle', { + defaultMessage: "Whoops! Looks like something isn't working properly.", + }), + children: ( + + {help.length ? ( + + +

{help.join('\n')}

+
+
+ ) : null} + {logs.length ? ( + + + + + {logs} + + ) : null} +
+ ), + status: 'danger', + }); + } + + let flyout; + if (isFlyoutVisible) { + flyout = ( + + + +

+ +

+
+ + + + +
+ + + +
+ ); + } + return ( +
+ {flyout} + + + +
+ ); +}; diff --git a/x-pack/plugins/reporting/public/components/report_listing.tsx b/x-pack/plugins/reporting/public/components/report_listing.tsx index afcae93a8db1..65db13f22788 100644 --- a/x-pack/plugins/reporting/public/components/report_listing.tsx +++ b/x-pack/plugins/reporting/public/components/report_listing.tsx @@ -6,6 +6,8 @@ import { EuiBasicTable, + EuiFlexItem, + EuiFlexGroup, EuiPageContent, EuiSpacer, EuiText, @@ -31,6 +33,7 @@ import { ReportErrorButton, ReportInfoButton, } from './buttons'; +import { ReportDiagnostic } from './report_diagnostic'; export interface Job { id: string; @@ -134,23 +137,38 @@ class ReportListingUi extends Component { public render() { return ( - - -

- -

-
- -

- -

-
- - {this.renderTable()} -
+
+ + + + +

+ +

+
+ +

+ +

+
+
+
+ + {this.renderTable()} +
+ + + + + + +
); } diff --git a/x-pack/plugins/reporting/public/lib/reporting_api_client.ts b/x-pack/plugins/reporting/public/lib/reporting_api_client.ts index 54bdc9953232..2f813bd811c6 100644 --- a/x-pack/plugins/reporting/public/lib/reporting_api_client.ts +++ b/x-pack/plugins/reporting/public/lib/reporting_api_client.ts @@ -8,7 +8,12 @@ import { stringify } from 'query-string'; import rison from 'rison-node'; import { HttpSetup } from 'src/core/public'; import { JobId, SourceJob } from '../../common/types'; -import { API_BASE_GENERATE, API_LIST_URL, REPORTING_MANAGEMENT_HOME } from '../../constants'; +import { + API_BASE_URL, + API_BASE_GENERATE, + API_LIST_URL, + REPORTING_MANAGEMENT_HOME, +} from '../../constants'; import { add } from './job_completion_notifications'; export interface JobQueueEntry { @@ -59,6 +64,12 @@ interface JobParams { [paramName: string]: any; } +export interface DiagnoseResponse { + help: string[]; + success: boolean; + logs: string; +} + export class ReportingAPIClient { private http: HttpSetup; @@ -157,4 +168,28 @@ export class ReportingAPIClient { * provides the raw server basePath to allow it to be stripped out from relativeUrls in job params */ public getServerBasePath = () => this.http.basePath.serverBasePath; + + /* + * Diagnostic-related API calls + */ + public verifyConfig = (): Promise => + this.http.post(`${API_BASE_URL}/diagnose/config`, { + asSystemRequest: true, + }); + + /* + * Diagnostic-related API calls + */ + public verifyBrowser = (): Promise => + this.http.post(`${API_BASE_URL}/diagnose/browser`, { + asSystemRequest: true, + }); + + /* + * Diagnostic-related API calls + */ + public verifyScreenCapture = (): Promise => + this.http.post(`${API_BASE_URL}/diagnose/screenshot`, { + asSystemRequest: true, + }); } diff --git a/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts b/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts index 809bfb57dd4f..88be86d1ecc3 100644 --- a/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts +++ b/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts @@ -59,28 +59,6 @@ export class HeadlessChromiumDriverFactory { type = BROWSER_TYPE; - test(logger: LevelLogger) { - const chromiumArgs = args({ - userDataDir: this.userDataDir, - viewport: { width: 800, height: 600 }, - disableSandbox: this.browserConfig.disableSandbox, - proxy: this.browserConfig.proxy, - }); - - return puppeteerLaunch({ - userDataDir: this.userDataDir, - executablePath: this.binaryPath, - ignoreHTTPSErrors: true, - args: chromiumArgs, - } as LaunchOptions).catch((error: Error) => { - logger.error( - `The Reporting plugin encountered issues launching Chromium in a self-test. You may have trouble generating reports.` - ); - logger.error(error); - return null; - }); - } - /* * Return an observable to objects which will drive screenshot capture for a page */ diff --git a/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/start_logs.ts b/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/start_logs.ts new file mode 100644 index 000000000000..8eafbd8e0ddb --- /dev/null +++ b/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/start_logs.ts @@ -0,0 +1,133 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { spawn } from 'child_process'; +import del from 'del'; +import { mkdtempSync } from 'fs'; +import { uniq } from 'lodash'; +import { tmpdir } from 'os'; +import { join } from 'path'; +import { createInterface } from 'readline'; +import { fromEvent, timer, merge, of } from 'rxjs'; +import { takeUntil, map, reduce, tap, catchError } from 'rxjs/operators'; +import { ReportingCore } from '../../..'; +import { LevelLogger } from '../../../lib'; +import { getBinaryPath } from '../../install'; +import { args } from './args'; + +const browserLaunchTimeToWait = 5 * 1000; + +// Default args used by pptr +// https://github.com/puppeteer/puppeteer/blob/13ea347/src/node/Launcher.ts#L168 +const defaultArgs = [ + '--disable-background-networking', + '--enable-features=NetworkService,NetworkServiceInProcess', + '--disable-background-timer-throttling', + '--disable-backgrounding-occluded-windows', + '--disable-breakpad', + '--disable-client-side-phishing-detection', + '--disable-component-extensions-with-background-pages', + '--disable-default-apps', + '--disable-dev-shm-usage', + '--disable-extensions', + '--disable-features=TranslateUI', + '--disable-hang-monitor', + '--disable-ipc-flooding-protection', + '--disable-popup-blocking', + '--disable-prompt-on-repost', + '--disable-renderer-backgrounding', + '--disable-sync', + '--force-color-profile=srgb', + '--metrics-recording-only', + '--no-first-run', + '--enable-automation', + '--password-store=basic', + '--use-mock-keychain', + '--remote-debugging-port=0', + '--headless', +]; + +export const browserStartLogs = ( + core: ReportingCore, + logger: LevelLogger, + overrideFlags: string[] = [] +) => { + const config = core.getConfig(); + const proxy = config.get('capture', 'browser', 'chromium', 'proxy'); + const disableSandbox = config.get('capture', 'browser', 'chromium', 'disableSandbox'); + const userDataDir = mkdtempSync(join(tmpdir(), 'chromium-')); + const binaryPath = getBinaryPath(); + const kbnArgs = args({ + userDataDir, + viewport: { width: 800, height: 600 }, + disableSandbox, + proxy, + }); + const finalArgs = uniq([...defaultArgs, ...kbnArgs, ...overrideFlags]); + + // On non-windows platforms, `detached: true` makes child process a + // leader of a new process group, making it possible to kill child + // process tree with `.kill(-pid)` command. @see + // https://nodejs.org/api/child_process.html#child_process_options_detached + const browserProcess = spawn(binaryPath, finalArgs, { + detached: process.platform !== 'win32', + }); + + const rl = createInterface({ input: browserProcess.stderr }); + + const exit$ = fromEvent(browserProcess, 'exit').pipe( + map((code) => { + logger.error(`Browser exited abnormally, received code: ${code}`); + return i18n.translate('xpack.reporting.diagnostic.browserCrashed', { + defaultMessage: `Browser exited abnormally during startup`, + }); + }) + ); + + const error$ = fromEvent(browserProcess, 'error').pipe( + map(() => { + logger.error(`Browser process threw an error on startup`); + return i18n.translate('xpack.reporting.diagnostic.browserErrored', { + defaultMessage: `Browser process threw an error on startup`, + }); + }) + ); + + const browserProcessLogger = logger.clone(['chromium-stderr']); + const log$ = fromEvent(rl, 'line').pipe( + tap((message: unknown) => { + if (typeof message === 'string') { + browserProcessLogger.info(message); + } + }) + ); + + // Collect all events (exit, error and on log-lines), but let chromium keep spitting out + // logs as sometimes it's "bind" successfully for remote connections, but later emit + // a log indicative of an issue (for example, no default font found). + return merge(exit$, error$, log$).pipe( + takeUntil(timer(browserLaunchTimeToWait)), + reduce((acc, curr) => `${acc}${curr}\n`, ''), + tap(() => { + if (browserProcess && browserProcess.pid && !browserProcess.killed) { + browserProcess.kill('SIGKILL'); + logger.info(`Successfully sent 'SIGKILL' to browser process (PID: ${browserProcess.pid})`); + } + browserProcess.removeAllListeners(); + rl.removeAllListeners(); + rl.close(); + del(userDataDir, { force: true }).catch((error) => { + logger.error(`Error deleting user data directory at [${userDataDir}]!`); + logger.error(error); + }); + }), + catchError((error) => { + logger.error(error); + return of(error); + }) + ); +}; diff --git a/x-pack/plugins/reporting/server/browsers/install.ts b/x-pack/plugins/reporting/server/browsers/install.ts index 9eddbe5ef049..35cc5b6d8b7c 100644 --- a/x-pack/plugins/reporting/server/browsers/install.ts +++ b/x-pack/plugins/reporting/server/browsers/install.ts @@ -4,24 +4,43 @@ * you may not use this file except in compliance with the Elastic License. */ +import del from 'del'; import os from 'os'; import path from 'path'; -import del from 'del'; - import * as Rx from 'rxjs'; import { LevelLogger } from '../lib'; +import { paths } from './chromium/paths'; import { ensureBrowserDownloaded } from './download'; // @ts-ignore import { md5 } from './download/checksum'; // @ts-ignore import { extract } from './extract'; -import { paths } from './chromium/paths'; interface Package { platforms: string[]; architecture: string; } +/** + * Small helper util to resolve where chromium is installed + */ +export const getBinaryPath = ( + chromiumPath: string = path.resolve(__dirname, '../../chromium'), + platform: string = process.platform, + architecture: string = os.arch() +) => { + const pkg = paths.packages.find((p: Package) => { + return p.platforms.includes(platform) && p.architecture === architecture; + }); + + if (!pkg) { + // TODO: validate this + throw new Error(`Unsupported platform: ${platform}-${architecture}`); + } + + return path.join(chromiumPath, pkg.binaryRelativePath); +}; + /** * "install" a browser by type into installs path by extracting the downloaded * archive. If there is an error extracting the archive an `ExtractError` is thrown @@ -43,7 +62,7 @@ export function installBrowser( throw new Error(`Unsupported platform: ${platform}-${architecture}`); } - const binaryPath = path.join(chromiumPath, pkg.binaryRelativePath); + const binaryPath = getBinaryPath(chromiumPath, platform, architecture); const binaryChecksum = await md5(binaryPath).catch(() => ''); if (binaryChecksum !== pkg.binaryChecksum) { diff --git a/x-pack/plugins/reporting/server/export_types/png/lib/generate_png.ts b/x-pack/plugins/reporting/server/export_types/png/lib/generate_png.ts index c3d5b2cc6005..096d0bd42821 100644 --- a/x-pack/plugins/reporting/server/export_types/png/lib/generate_png.ts +++ b/x-pack/plugins/reporting/server/export_types/png/lib/generate_png.ts @@ -28,7 +28,7 @@ export async function generatePngObservableFactory(reporting: ReportingCore) { if (!layoutParams || !layoutParams.dimensions) { throw new Error(`LayoutParams.Dimensions is undefined.`); } - const layout = new PreserveLayout(layoutParams.dimensions); + const layout = new PreserveLayout(layoutParams.dimensions, layoutParams.selectors); if (apmLayout) apmLayout.end(); const apmScreenshots = apmTrans?.startSpan('screenshots_pipeline', 'setup'); diff --git a/x-pack/plugins/reporting/server/lib/index.ts b/x-pack/plugins/reporting/server/lib/index.ts index f3a09cffbb10..9e5a3ca76126 100644 --- a/x-pack/plugins/reporting/server/lib/index.ts +++ b/x-pack/plugins/reporting/server/lib/index.ts @@ -13,4 +13,3 @@ export { LevelLogger } from './level_logger'; export { statuses } from './statuses'; export { ReportingStore } from './store'; export { startTrace } from './trace'; -export { runValidations } from './validate'; diff --git a/x-pack/plugins/reporting/server/lib/layouts/index.ts b/x-pack/plugins/reporting/server/lib/layouts/index.ts index d46f08847522..507b7614072e 100644 --- a/x-pack/plugins/reporting/server/lib/layouts/index.ts +++ b/x-pack/plugins/reporting/server/lib/layouts/index.ts @@ -54,6 +54,7 @@ export interface Size { export interface LayoutParams { id: string; dimensions: Size; + selectors?: LayoutSelectorDictionary; } interface LayoutSelectors { diff --git a/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.ts b/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.ts index 9041055ddce2..e8d182dac0b1 100644 --- a/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.ts +++ b/x-pack/plugins/reporting/server/lib/layouts/preserve_layout.ts @@ -25,12 +25,16 @@ export class PreserveLayout extends Layout { private readonly scaledHeight: number; private readonly scaledWidth: number; - constructor(size: Size) { + constructor(size: Size, layoutSelectors?: LayoutSelectorDictionary) { super(LayoutTypes.PRESERVE_LAYOUT); this.height = size.height; this.width = size.width; this.scaledHeight = size.height * ZOOM; this.scaledWidth = size.width * ZOOM; + + if (layoutSelectors) { + this.selectors = layoutSelectors; + } } public getCssOverridesPath() { diff --git a/x-pack/plugins/reporting/server/lib/store/store.test.ts b/x-pack/plugins/reporting/server/lib/store/store.test.ts index e6c4eb734646..b87466ca289c 100644 --- a/x-pack/plugins/reporting/server/lib/store/store.test.ts +++ b/x-pack/plugins/reporting/server/lib/store/store.test.ts @@ -7,8 +7,7 @@ import sinon from 'sinon'; import { ElasticsearchServiceSetup } from 'src/core/server'; import { ReportingConfig, ReportingCore } from '../..'; -import { createMockReportingCore } from '../../test_helpers'; -import { createMockLevelLogger } from '../../test_helpers/create_mock_levellogger'; +import { createMockReportingCore, createMockLevelLogger } from '../../test_helpers'; import { Report } from './report'; import { ReportingStore } from './store'; diff --git a/x-pack/plugins/reporting/server/lib/validate/index.ts b/x-pack/plugins/reporting/server/lib/validate/index.ts deleted file mode 100644 index d20df6b7315b..000000000000 --- a/x-pack/plugins/reporting/server/lib/validate/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; -import { ElasticsearchServiceSetup } from 'kibana/server'; -import { ReportingConfig } from '../../'; -import { HeadlessChromiumDriverFactory } from '../../browsers/chromium/driver_factory'; -import { LevelLogger } from '../'; -import { validateBrowser } from './validate_browser'; -import { validateMaxContentLength } from './validate_max_content_length'; - -export async function runValidations( - config: ReportingConfig, - elasticsearch: ElasticsearchServiceSetup, - browserFactory: HeadlessChromiumDriverFactory, - parentLogger: LevelLogger -) { - const logger = parentLogger.clone(['validations']); - try { - await Promise.all([ - validateBrowser(browserFactory, logger), - validateMaxContentLength(config, elasticsearch, logger), - ]); - logger.debug( - i18n.translate('xpack.reporting.selfCheck.ok', { - defaultMessage: `Reporting plugin self-check ok!`, - }) - ); - } catch (err) { - logger.error(err); - logger.warning( - i18n.translate('xpack.reporting.selfCheck.warning', { - defaultMessage: `Reporting plugin self-check generated a warning: {err}`, - values: { - err, - }, - }) - ); - } -} diff --git a/x-pack/plugins/reporting/server/lib/validate/validate_browser.ts b/x-pack/plugins/reporting/server/lib/validate/validate_browser.ts deleted file mode 100644 index d29aa522dad9..000000000000 --- a/x-pack/plugins/reporting/server/lib/validate/validate_browser.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { Browser } from 'puppeteer'; -import { BROWSER_TYPE } from '../../../common/constants'; -import { HeadlessChromiumDriverFactory } from '../../browsers/chromium/driver_factory'; -import { LevelLogger } from '../'; - -/* - * Validate the Reporting headless browser can launch, and that it can connect - * to the locally running Kibana instance. - */ -export const validateBrowser = async ( - browserFactory: HeadlessChromiumDriverFactory, - logger: LevelLogger -) => { - if (browserFactory.type === BROWSER_TYPE) { - return browserFactory.test(logger).then((browser: Browser | null) => { - if (browser && browser.close) { - browser.close(); - } else { - throw new Error('Could not close browser client handle!'); - } - }); - } -}; diff --git a/x-pack/plugins/reporting/server/lib/validate/validate_max_content_length.test.js b/x-pack/plugins/reporting/server/lib/validate/validate_max_content_length.test.js deleted file mode 100644 index f358021560cf..000000000000 --- a/x-pack/plugins/reporting/server/lib/validate/validate_max_content_length.test.js +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import sinon from 'sinon'; -import { validateMaxContentLength } from './validate_max_content_length'; - -const FIVE_HUNDRED_MEGABYTES = 524288000; -const ONE_HUNDRED_MEGABYTES = 104857600; - -describe('Reporting: Validate Max Content Length', () => { - const elasticsearch = { - legacy: { - client: { - callAsInternalUser: () => ({ - defaults: { - http: { - max_content_length: '100mb', - }, - }, - }), - }, - }, - }; - - const logger = { - warning: sinon.spy(), - }; - - beforeEach(() => { - logger.warning.resetHistory(); - }); - - it('should log warning messages when reporting has a higher max-size than elasticsearch', async () => { - const config = { get: sinon.stub().returns(FIVE_HUNDRED_MEGABYTES) }; - const elasticsearch = { - legacy: { - client: { - callAsInternalUser: () => ({ - defaults: { - http: { - max_content_length: '100mb', - }, - }, - }), - }, - }, - }; - - await validateMaxContentLength(config, elasticsearch, logger); - - sinon.assert.calledWithMatch( - logger.warning, - `xpack.reporting.csv.maxSizeBytes (524288000) is higher` - ); - sinon.assert.calledWithMatch( - logger.warning, - `than ElasticSearch's http.max_content_length (104857600)` - ); - sinon.assert.calledWithMatch( - logger.warning, - 'Please set http.max_content_length in ElasticSearch to match' - ); - sinon.assert.calledWithMatch( - logger.warning, - 'or lower your xpack.reporting.csv.maxSizeBytes in Kibana' - ); - }); - - it('should do nothing when reporting has the same max-size as elasticsearch', async () => { - const config = { get: sinon.stub().returns(ONE_HUNDRED_MEGABYTES) }; - - expect( - async () => await validateMaxContentLength(config, elasticsearch, logger.warning) - ).not.toThrow(); - sinon.assert.notCalled(logger.warning); - }); -}); diff --git a/x-pack/plugins/reporting/server/lib/validate/validate_max_content_length.ts b/x-pack/plugins/reporting/server/lib/validate/validate_max_content_length.ts deleted file mode 100644 index c38c6e529785..000000000000 --- a/x-pack/plugins/reporting/server/lib/validate/validate_max_content_length.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import numeral from '@elastic/numeral'; -import { ElasticsearchServiceSetup } from 'kibana/server'; -import { defaults, get } from 'lodash'; -import { ReportingConfig } from '../../'; -import { LevelLogger } from '../'; - -const KIBANA_MAX_SIZE_BYTES_PATH = 'csv.maxSizeBytes'; -const ES_MAX_SIZE_BYTES_PATH = 'http.max_content_length'; - -export async function validateMaxContentLength( - config: ReportingConfig, - elasticsearch: ElasticsearchServiceSetup, - logger: LevelLogger -) { - const { callAsInternalUser } = elasticsearch.legacy.client; - - const elasticClusterSettingsResponse = await callAsInternalUser('cluster.getSettings', { - includeDefaults: true, - }); - const { persistent, transient, defaults: defaultSettings } = elasticClusterSettingsResponse; - const elasticClusterSettings = defaults({}, persistent, transient, defaultSettings); - - const elasticSearchMaxContent = get(elasticClusterSettings, 'http.max_content_length', '100mb'); - const elasticSearchMaxContentBytes = numeral().unformat(elasticSearchMaxContent.toUpperCase()); - const kibanaMaxContentBytes = config.get('csv', 'maxSizeBytes'); - - if (kibanaMaxContentBytes > elasticSearchMaxContentBytes) { - // TODO this should simply throw an error and let the handler conver it to a warning mesasge. See validateServerHost. - logger.warning( - `xpack.reporting.${KIBANA_MAX_SIZE_BYTES_PATH} (${kibanaMaxContentBytes}) is higher than ElasticSearch's ${ES_MAX_SIZE_BYTES_PATH} (${elasticSearchMaxContentBytes}). ` + - `Please set ${ES_MAX_SIZE_BYTES_PATH} in ElasticSearch to match, or lower your xpack.reporting.${KIBANA_MAX_SIZE_BYTES_PATH} in Kibana to avoid this warning.` - ); - } -} diff --git a/x-pack/plugins/reporting/server/plugin.ts b/x-pack/plugins/reporting/server/plugin.ts index 8c0e352aa06c..af1ccfd592b9 100644 --- a/x-pack/plugins/reporting/server/plugin.ts +++ b/x-pack/plugins/reporting/server/plugin.ts @@ -11,7 +11,7 @@ import { PLUGIN_ID, UI_SETTINGS_CUSTOM_PDF_LOGO } from '../common/constants'; import { ReportingCore } from './'; import { initializeBrowserDriverFactory } from './browsers'; import { buildConfig, ReportingConfigType } from './config'; -import { createQueueFactory, LevelLogger, ReportingStore, runValidations } from './lib'; +import { createQueueFactory, LevelLogger, ReportingStore } from './lib'; import { registerRoutes } from './routes'; import { setFieldFormats } from './services'; import { ReportingSetup, ReportingSetupDeps, ReportingStart, ReportingStartDeps } from './types'; @@ -105,7 +105,6 @@ export class ReportingPlugin setFieldFormats(plugins.data.fieldFormats); const { logger, reportingCore } = this; - const { elasticsearch } = reportingCore.getPluginSetupDeps(); // async background start (async () => { @@ -124,9 +123,6 @@ export class ReportingPlugin store, }); - // run self-check validations - runValidations(config, elasticsearch, browserDriverFactory, this.logger); - this.logger.debug('Start complete'); })().catch((e) => { this.logger.error(`Error in Reporting start, reporting may not function properly`); diff --git a/x-pack/plugins/reporting/server/routes/diagnostic/browser.test.ts b/x-pack/plugins/reporting/server/routes/diagnostic/browser.test.ts new file mode 100644 index 000000000000..f92fbfc7013c --- /dev/null +++ b/x-pack/plugins/reporting/server/routes/diagnostic/browser.test.ts @@ -0,0 +1,250 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { UnwrapPromise } from '@kbn/utility-types'; +import { spawn } from 'child_process'; +import { createInterface } from 'readline'; +import { setupServer } from 'src/core/server/test_utils'; +import supertest from 'supertest'; +import { ReportingCore } from '../..'; +import { createMockLevelLogger, createMockReportingCore } from '../../test_helpers'; +import { registerDiagnoseBrowser } from './browser'; + +jest.mock('child_process'); +jest.mock('readline'); + +type SetupServerReturn = UnwrapPromise>; + +const devtoolMessage = 'DevTools listening on (ws://localhost:4000)'; +const fontNotFoundMessage = 'Could not find the default font'; + +describe('POST /diagnose/browser', () => { + jest.setTimeout(6000); + const reportingSymbol = Symbol('reporting'); + const mockLogger = createMockLevelLogger(); + + let server: SetupServerReturn['server']; + let httpSetup: SetupServerReturn['httpSetup']; + let core: ReportingCore; + const mockedSpawn: any = spawn; + const mockedCreateInterface: any = createInterface; + + const config = { + get: jest.fn().mockImplementation(() => ({})), + kbnConfig: { get: jest.fn() }, + }; + + beforeEach(async () => { + ({ server, httpSetup } = await setupServer(reportingSymbol)); + httpSetup.registerRouteHandlerContext(reportingSymbol, 'reporting', () => ({})); + + const mockSetupDeps = ({ + elasticsearch: { + legacy: { client: { callAsInternalUser: jest.fn() } }, + }, + router: httpSetup.createRouter(''), + } as unknown) as any; + + core = await createMockReportingCore(config, mockSetupDeps); + + mockedSpawn.mockImplementation(() => ({ + removeAllListeners: jest.fn(), + kill: jest.fn(), + pid: 123, + stderr: 'stderr', + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + })); + + mockedCreateInterface.mockImplementation(() => ({ + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + removeAllListeners: jest.fn(), + close: jest.fn(), + })); + }); + + afterEach(async () => { + await server.stop(); + }); + + it('returns a 200 when successful', async () => { + registerDiagnoseBrowser(core, mockLogger); + + await server.start(); + + mockedCreateInterface.mockImplementation(() => ({ + addEventListener: (e: string, cb: any) => setTimeout(() => cb(devtoolMessage), 0), + removeEventListener: jest.fn(), + removeAllListeners: jest.fn(), + close: jest.fn(), + })); + + return supertest(httpSetup.server.listener) + .post('/api/reporting/diagnose/browser') + .expect(200) + .then(({ body }) => { + expect(body.success).toEqual(true); + expect(body.help).toEqual([]); + }); + }); + + it('returns logs when browser crashes + helpful links', async () => { + const logs = `Could not find the default font`; + registerDiagnoseBrowser(core, mockLogger); + + await server.start(); + + mockedCreateInterface.mockImplementation(() => ({ + addEventListener: (e: string, cb: any) => setTimeout(() => cb(logs), 0), + removeEventListener: jest.fn(), + removeAllListeners: jest.fn(), + close: jest.fn(), + })); + + mockedSpawn.mockImplementation(() => ({ + removeAllListeners: jest.fn(), + kill: jest.fn(), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + })); + + return supertest(httpSetup.server.listener) + .post('/api/reporting/diagnose/browser') + .expect(200) + .then(({ body }) => { + expect(body).toMatchInlineSnapshot(` + Object { + "help": Array [ + "The browser couldn't locate a default font. Please see https://www.elastic.co/guide/en/kibana/current/reporting-troubleshooting.html#reporting-troubleshooting-system-dependencies to fix this issue.", + ], + "logs": "Could not find the default font + ", + "success": false, + } + `); + }); + }); + + it('logs a message when the browser starts, but then has problems later', async () => { + registerDiagnoseBrowser(core, mockLogger); + + await server.start(); + + mockedCreateInterface.mockImplementation(() => ({ + addEventListener: (e: string, cb: any) => { + setTimeout(() => cb(devtoolMessage), 0); + setTimeout(() => cb(fontNotFoundMessage), 0); + }, + removeEventListener: jest.fn(), + removeAllListeners: jest.fn(), + close: jest.fn(), + })); + + mockedSpawn.mockImplementation(() => ({ + removeAllListeners: jest.fn(), + kill: jest.fn(), + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + })); + + return supertest(httpSetup.server.listener) + .post('/api/reporting/diagnose/browser') + .expect(200) + .then(({ body }) => { + expect(body).toMatchInlineSnapshot(` + Object { + "help": Array [ + "The browser couldn't locate a default font. Please see https://www.elastic.co/guide/en/kibana/current/reporting-troubleshooting.html#reporting-troubleshooting-system-dependencies to fix this issue.", + ], + "logs": "DevTools listening on (ws://localhost:4000) + Could not find the default font + ", + "success": false, + } + `); + }); + }); + + it('logs a message when the browser starts, but then crashes', async () => { + registerDiagnoseBrowser(core, mockLogger); + + await server.start(); + + mockedCreateInterface.mockImplementation(() => ({ + addEventListener: (e: string, cb: any) => { + setTimeout(() => cb(fontNotFoundMessage), 0); + }, + removeEventListener: jest.fn(), + removeAllListeners: jest.fn(), + close: jest.fn(), + })); + + mockedSpawn.mockImplementation(() => ({ + removeAllListeners: jest.fn(), + kill: jest.fn(), + addEventListener: (e: string, cb: any) => { + if (e === 'exit') { + setTimeout(() => cb(), 5); + } + }, + removeEventListener: jest.fn(), + })); + + return supertest(httpSetup.server.listener) + .post('/api/reporting/diagnose/browser') + .expect(200) + .then(({ body }) => { + expect(body).toMatchInlineSnapshot(` + Object { + "help": Array [ + "The browser couldn't locate a default font. Please see https://www.elastic.co/guide/en/kibana/current/reporting-troubleshooting.html#reporting-troubleshooting-system-dependencies to fix this issue.", + ], + "logs": "Could not find the default font + Browser exited abnormally during startup + ", + "success": false, + } + `); + }); + }); + + it('cleans up process and subscribers', async () => { + registerDiagnoseBrowser(core, mockLogger); + + await server.start(); + const killMock = jest.fn(); + const spawnListenersMock = jest.fn(); + const createInterfaceListenersMock = jest.fn(); + const createInterfaceCloseMock = jest.fn(); + + mockedSpawn.mockImplementation(() => ({ + removeAllListeners: spawnListenersMock, + kill: killMock, + pid: 123, + stderr: 'stderr', + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + })); + + mockedCreateInterface.mockImplementation(() => ({ + addEventListener: (e: string, cb: any) => setTimeout(() => cb(devtoolMessage), 0), + removeEventListener: jest.fn(), + removeAllListeners: createInterfaceListenersMock, + close: createInterfaceCloseMock, + })); + + return supertest(httpSetup.server.listener) + .post('/api/reporting/diagnose/browser') + .expect(200) + .then(() => { + expect(killMock.mock.calls.length).toBe(1); + expect(spawnListenersMock.mock.calls.length).toBe(1); + expect(createInterfaceListenersMock.mock.calls.length).toBe(1); + expect(createInterfaceCloseMock.mock.calls.length).toBe(1); + }); + }); +}); diff --git a/x-pack/plugins/reporting/server/routes/diagnostic/browser.ts b/x-pack/plugins/reporting/server/routes/diagnostic/browser.ts new file mode 100644 index 000000000000..24b85220defb --- /dev/null +++ b/x-pack/plugins/reporting/server/routes/diagnostic/browser.ts @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { ReportingCore } from '../..'; +import { API_DIAGNOSE_URL } from '../../../common/constants'; +import { browserStartLogs } from '../../browsers/chromium/driver_factory/start_logs'; +import { LevelLogger as Logger } from '../../lib'; +import { DiagnosticResponse } from '../../types'; +import { authorizedUserPreRoutingFactory } from '../lib/authorized_user_pre_routing'; + +const logsToHelpMap = { + 'error while loading shared libraries': i18n.translate( + 'xpack.reporting.diagnostic.browserMissingDependency', + { + defaultMessage: `The browser couldn't start properly due to missing system dependencies. Please see {url}`, + values: { + url: + 'https://www.elastic.co/guide/en/kibana/current/reporting-troubleshooting.html#reporting-troubleshooting-system-dependencies', + }, + } + ), + + 'Could not find the default font': i18n.translate( + 'xpack.reporting.diagnostic.browserMissingFonts', + { + defaultMessage: `The browser couldn't locate a default font. Please see {url} to fix this issue.`, + values: { + url: + 'https://www.elastic.co/guide/en/kibana/current/reporting-troubleshooting.html#reporting-troubleshooting-system-dependencies', + }, + } + ), + + 'No usable sandbox': i18n.translate('xpack.reporting.diagnostic.noUsableSandbox', { + defaultMessage: `Unable to use Chromium sandbox. This can be disabled at your own risk with 'xpack.reporting.capture.browser.chromium.disableSandbox'. Please see {url}`, + values: { + url: + 'https://www.elastic.co/guide/en/kibana/current/reporting-troubleshooting.html#reporting-troubleshooting-sandbox-dependency', + }, + }), +}; + +export const registerDiagnoseBrowser = (reporting: ReportingCore, logger: Logger) => { + const { router } = reporting.getPluginSetupDeps(); + const userHandler = authorizedUserPreRoutingFactory(reporting); + + router.post( + { + path: `${API_DIAGNOSE_URL}/browser`, + validate: {}, + }, + userHandler(async (user, context, req, res) => { + const logs = await browserStartLogs(reporting, logger).toPromise(); + const knownIssues = Object.keys(logsToHelpMap) as Array; + + const boundSuccessfully = logs.includes(`DevTools listening on`); + const help = knownIssues.reduce((helpTexts: string[], knownIssue) => { + const helpText = logsToHelpMap[knownIssue]; + if (logs.includes(knownIssue)) { + helpTexts.push(helpText); + } + return helpTexts; + }, []); + + const response: DiagnosticResponse = { + success: boundSuccessfully && !help.length, + help, + logs, + }; + + return res.ok({ body: response }); + }) + ); +}; diff --git a/x-pack/plugins/reporting/server/routes/diagnostic/config.test.ts b/x-pack/plugins/reporting/server/routes/diagnostic/config.test.ts new file mode 100644 index 000000000000..624397246656 --- /dev/null +++ b/x-pack/plugins/reporting/server/routes/diagnostic/config.test.ts @@ -0,0 +1,107 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { UnwrapPromise } from '@kbn/utility-types'; +import { setupServer } from 'src/core/server/test_utils'; +import supertest from 'supertest'; +import { ReportingCore } from '../..'; +import { createMockReportingCore, createMockLevelLogger } from '../../test_helpers'; +import { registerDiagnoseConfig } from './config'; + +type SetupServerReturn = UnwrapPromise>; + +describe('POST /diagnose/config', () => { + const reportingSymbol = Symbol('reporting'); + let server: SetupServerReturn['server']; + let httpSetup: SetupServerReturn['httpSetup']; + let core: ReportingCore; + let mockSetupDeps: any; + let config: any; + + const mockLogger = createMockLevelLogger(); + + beforeEach(async () => { + ({ server, httpSetup } = await setupServer(reportingSymbol)); + httpSetup.registerRouteHandlerContext(reportingSymbol, 'reporting', () => ({})); + + mockSetupDeps = ({ + elasticsearch: { + legacy: { client: { callAsInternalUser: jest.fn() } }, + }, + router: httpSetup.createRouter(''), + } as unknown) as any; + + config = { + get: jest.fn(), + kbnConfig: { get: jest.fn() }, + }; + + core = await createMockReportingCore(config, mockSetupDeps); + }); + + afterEach(async () => { + await server.stop(); + }); + + it('returns a 200 by default when configured properly', async () => { + mockSetupDeps.elasticsearch.legacy.client.callAsInternalUser.mockImplementation(() => + Promise.resolve({ + defaults: { + http: { + max_content_length: '100mb', + }, + }, + }) + ); + registerDiagnoseConfig(core, mockLogger); + + await server.start(); + + await supertest(httpSetup.server.listener) + .post('/api/reporting/diagnose/config') + .expect(200) + .then(({ body }) => { + expect(body).toMatchInlineSnapshot(` + Object { + "help": Array [], + "logs": "", + "success": true, + } + `); + }); + }); + + it('returns a 200 with help text when not configured properly', async () => { + config.get.mockImplementation(() => 10485760); + mockSetupDeps.elasticsearch.legacy.client.callAsInternalUser.mockImplementation(() => + Promise.resolve({ + defaults: { + http: { + max_content_length: '5mb', + }, + }, + }) + ); + registerDiagnoseConfig(core, mockLogger); + + await server.start(); + + await supertest(httpSetup.server.listener) + .post('/api/reporting/diagnose/config') + .expect(200) + .then(({ body }) => { + expect(body).toMatchInlineSnapshot(` + Object { + "help": Array [ + "xpack.reporting.csv.maxSizeBytes (10485760) is higher than ElasticSearch's http.max_content_length (5242880). Please set http.max_content_length in ElasticSearch to match, or lower your xpack.reporting.csv.maxSizeBytes in Kibana.", + ], + "logs": "xpack.reporting.csv.maxSizeBytes (10485760) is higher than ElasticSearch's http.max_content_length (5242880). Please set http.max_content_length in ElasticSearch to match, or lower your xpack.reporting.csv.maxSizeBytes in Kibana.", + "success": false, + } + `); + }); + }); +}); diff --git a/x-pack/plugins/reporting/server/routes/diagnostic/config.ts b/x-pack/plugins/reporting/server/routes/diagnostic/config.ts new file mode 100644 index 000000000000..198ba63e2614 --- /dev/null +++ b/x-pack/plugins/reporting/server/routes/diagnostic/config.ts @@ -0,0 +1,81 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import numeral from '@elastic/numeral'; +import { defaults, get } from 'lodash'; +import { ReportingCore } from '../..'; +import { API_DIAGNOSE_URL } from '../../../common/constants'; +import { LevelLogger as Logger } from '../../lib'; +import { DiagnosticResponse } from '../../types'; +import { authorizedUserPreRoutingFactory } from '../lib/authorized_user_pre_routing'; + +const KIBANA_MAX_SIZE_BYTES_PATH = 'csv.maxSizeBytes'; +const ES_MAX_SIZE_BYTES_PATH = 'http.max_content_length'; + +export const registerDiagnoseConfig = (reporting: ReportingCore, logger: Logger) => { + const setupDeps = reporting.getPluginSetupDeps(); + const userHandler = authorizedUserPreRoutingFactory(reporting); + const { router, elasticsearch } = setupDeps; + + router.post( + { + path: `${API_DIAGNOSE_URL}/config`, + validate: {}, + }, + userHandler(async (user, context, req, res) => { + const warnings = []; + const { callAsInternalUser } = elasticsearch.legacy.client; + const config = reporting.getConfig(); + + const elasticClusterSettingsResponse = await callAsInternalUser('cluster.getSettings', { + includeDefaults: true, + }); + const { persistent, transient, defaults: defaultSettings } = elasticClusterSettingsResponse; + const elasticClusterSettings = defaults({}, persistent, transient, defaultSettings); + + const elasticSearchMaxContent = get( + elasticClusterSettings, + 'http.max_content_length', + '100mb' + ); + const elasticSearchMaxContentBytes = numeral().unformat( + elasticSearchMaxContent.toUpperCase() + ); + const kibanaMaxContentBytes = config.get('csv', 'maxSizeBytes'); + + if (kibanaMaxContentBytes > elasticSearchMaxContentBytes) { + const maxContentSizeWarning = i18n.translate( + 'xpack.reporting.diagnostic.configSizeMismatch', + { + defaultMessage: + `xpack.reporting.{KIBANA_MAX_SIZE_BYTES_PATH} ({kibanaMaxContentBytes}) is higher than ElasticSearch's {ES_MAX_SIZE_BYTES_PATH} ({elasticSearchMaxContentBytes}). ` + + `Please set {ES_MAX_SIZE_BYTES_PATH} in ElasticSearch to match, or lower your xpack.reporting.{KIBANA_MAX_SIZE_BYTES_PATH} in Kibana.`, + values: { + kibanaMaxContentBytes, + elasticSearchMaxContentBytes, + KIBANA_MAX_SIZE_BYTES_PATH, + ES_MAX_SIZE_BYTES_PATH, + }, + } + ); + warnings.push(maxContentSizeWarning); + } + + if (warnings.length) { + warnings.forEach((warn) => logger.warn(warn)); + } + + const body: DiagnosticResponse = { + help: warnings, + success: !warnings.length, + logs: warnings.join('\n'), + }; + + return res.ok({ body }); + }) + ); +}; diff --git a/x-pack/plugins/reporting/server/routes/diagnostic/index.ts b/x-pack/plugins/reporting/server/routes/diagnostic/index.ts new file mode 100644 index 000000000000..895dee32614f --- /dev/null +++ b/x-pack/plugins/reporting/server/routes/diagnostic/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { registerDiagnoseBrowser } from './browser'; +import { registerDiagnoseConfig } from './config'; +import { registerDiagnoseScreenshot } from './screenshot'; +import { LevelLogger as Logger } from '../../lib'; +import { ReportingCore } from '../../core'; + +export const registerDiagnosticRoutes = (reporting: ReportingCore, logger: Logger) => { + registerDiagnoseBrowser(reporting, logger); + registerDiagnoseConfig(reporting, logger); + registerDiagnoseScreenshot(reporting, logger); +}; diff --git a/x-pack/plugins/reporting/server/routes/diagnostic/screenshot.test.ts b/x-pack/plugins/reporting/server/routes/diagnostic/screenshot.test.ts new file mode 100644 index 000000000000..ec4ab0446ae5 --- /dev/null +++ b/x-pack/plugins/reporting/server/routes/diagnostic/screenshot.test.ts @@ -0,0 +1,112 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { UnwrapPromise } from '@kbn/utility-types'; +import { setupServer } from 'src/core/server/test_utils'; +import supertest from 'supertest'; +import { ReportingCore } from '../..'; +import { createMockReportingCore, createMockLevelLogger } from '../../test_helpers'; +import { registerDiagnoseScreenshot } from './screenshot'; + +jest.mock('../../export_types/png/lib/generate_png'); + +import { generatePngObservableFactory } from '../../export_types/png/lib/generate_png'; + +type SetupServerReturn = UnwrapPromise>; + +describe('POST /diagnose/screenshot', () => { + const reportingSymbol = Symbol('reporting'); + let server: SetupServerReturn['server']; + let httpSetup: SetupServerReturn['httpSetup']; + let core: ReportingCore; + + const setScreenshotResponse = (resp: object | Error) => { + const generateMock = Promise.resolve(() => ({ + pipe: () => ({ + toPromise: () => (resp instanceof Error ? Promise.reject(resp) : Promise.resolve(resp)), + }), + })); + (generatePngObservableFactory as any).mockResolvedValue(generateMock); + }; + + const config = { + get: jest.fn(), + kbnConfig: { get: jest.fn() }, + }; + const mockLogger = createMockLevelLogger(); + + beforeEach(async () => { + ({ server, httpSetup } = await setupServer(reportingSymbol)); + httpSetup.registerRouteHandlerContext(reportingSymbol, 'reporting', () => ({})); + + const mockSetupDeps = ({ + elasticsearch: { + legacy: { client: { callAsInternalUser: jest.fn() } }, + }, + router: httpSetup.createRouter(''), + } as unknown) as any; + + core = await createMockReportingCore(config, mockSetupDeps); + }); + + afterEach(async () => { + await server.stop(); + }); + + it('returns a 200 by default', async () => { + registerDiagnoseScreenshot(core, mockLogger); + setScreenshotResponse({ warnings: [] }); + await server.start(); + + await supertest(httpSetup.server.listener) + .post('/api/reporting/diagnose/screenshot') + .expect(200) + .then(({ body }) => { + expect(body).toMatchInlineSnapshot(` + Object { + "help": Array [], + "logs": "", + "success": true, + } + `); + }); + }); + + it('returns a 200 when it fails and sets success to false', async () => { + registerDiagnoseScreenshot(core, mockLogger); + setScreenshotResponse({ warnings: [`Timeout waiting for .dank to load`] }); + await server.start(); + + await supertest(httpSetup.server.listener) + .post('/api/reporting/diagnose/screenshot') + .expect(200) + .then(({ body }) => { + expect(body).toMatchInlineSnapshot(` + Object { + "help": Array [], + "logs": Array [ + "Timeout waiting for .dank to load", + ], + "success": false, + } + `); + }); + }); + + it('catches errors and returns a well formed response', async () => { + registerDiagnoseScreenshot(core, mockLogger); + setScreenshotResponse(new Error('Failure to start chromium!')); + await server.start(); + + await supertest(httpSetup.server.listener) + .post('/api/reporting/diagnose/screenshot') + .expect(200) + .then(({ body }) => { + expect(body.help).toContain(`We couldn't screenshot your Kibana install.`); + expect(body.logs).toContain(`Failure to start chromium!`); + }); + }); +}); diff --git a/x-pack/plugins/reporting/server/routes/diagnostic/screenshot.ts b/x-pack/plugins/reporting/server/routes/diagnostic/screenshot.ts new file mode 100644 index 000000000000..7e07779b5fd3 --- /dev/null +++ b/x-pack/plugins/reporting/server/routes/diagnostic/screenshot.ts @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { ReportingCore } from '../..'; +import { API_DIAGNOSE_URL } from '../../../common/constants'; +import { omitBlacklistedHeaders } from '../../export_types/common'; +import { getAbsoluteUrlFactory } from '../../export_types/common/get_absolute_url'; +import { generatePngObservableFactory } from '../../export_types/png/lib/generate_png'; +import { LevelLogger as Logger } from '../../lib'; +import { DiagnosticResponse } from '../../types'; +import { authorizedUserPreRoutingFactory } from '../lib/authorized_user_pre_routing'; + +export const registerDiagnoseScreenshot = (reporting: ReportingCore, logger: Logger) => { + const setupDeps = reporting.getPluginSetupDeps(); + const userHandler = authorizedUserPreRoutingFactory(reporting); + const { router } = setupDeps; + + router.post( + { + path: `${API_DIAGNOSE_URL}/screenshot`, + validate: {}, + }, + userHandler(async (user, context, req, res) => { + const generatePngObservable = await generatePngObservableFactory(reporting); + const config = reporting.getConfig(); + const decryptedHeaders = req.headers as Record; + const [basePath, protocol, hostname, port] = [ + config.kbnConfig.get('server', 'basePath'), + config.get('kibanaServer', 'protocol'), + config.get('kibanaServer', 'hostname'), + config.get('kibanaServer', 'port'), + ] as string[]; + + const getAbsoluteUrl = getAbsoluteUrlFactory({ + defaultBasePath: basePath, + protocol, + hostname, + port, + }); + + const hashUrl = getAbsoluteUrl({ + basePath, + path: '/', + hash: '', + search: '', + }); + + // Hack the layout to make the base/login page work + const layout = { + id: 'png', + dimensions: { + width: 1440, + height: 2024, + }, + selectors: { + screenshot: '.application', + renderComplete: '.application', + itemsCountAttribute: 'data-test-subj="kibanaChrome"', + timefilterDurationAttribute: 'data-test-subj="kibanaChrome"', + }, + }; + + const headers = { + headers: omitBlacklistedHeaders({ + job: null, + decryptedHeaders, + }), + conditions: { + hostname, + port: +port, + basePath, + protocol, + }, + }; + + return generatePngObservable(logger, hashUrl, 'America/Los_Angeles', headers, layout) + .pipe() + .toPromise() + .then((screenshot) => { + if (screenshot.warnings.length) { + return res.ok({ + body: { + success: false, + help: [], + logs: screenshot.warnings, + }, + }); + } + return res.ok({ + body: { + success: true, + help: [], + logs: '', + } as DiagnosticResponse, + }); + }) + .catch((error) => + res.ok({ + body: { + success: false, + help: [ + i18n.translate('xpack.reporting.diagnostic.screenshotFailureMessage', { + defaultMessage: `We couldn't screenshot your Kibana install.`, + }), + ], + logs: error.message, + } as DiagnosticResponse, + }) + ); + }) + ); +}; diff --git a/x-pack/plugins/reporting/server/routes/generation.test.ts b/x-pack/plugins/reporting/server/routes/generation.test.ts index 0db0073149e5..dd905223a81d 100644 --- a/x-pack/plugins/reporting/server/routes/generation.test.ts +++ b/x-pack/plugins/reporting/server/routes/generation.test.ts @@ -11,8 +11,7 @@ import { setupServer } from 'src/core/server/test_utils'; import supertest from 'supertest'; import { ReportingCore } from '..'; import { ExportTypesRegistry } from '../lib/export_types_registry'; -import { createMockReportingCore } from '../test_helpers'; -import { createMockLevelLogger } from '../test_helpers/create_mock_levellogger'; +import { createMockReportingCore, createMockLevelLogger } from '../test_helpers'; import { registerJobGenerationRoutes } from './generation'; type SetupServerReturn = UnwrapPromise>; diff --git a/x-pack/plugins/reporting/server/routes/index.ts b/x-pack/plugins/reporting/server/routes/index.ts index 005d82086665..11ad4cc9d4eb 100644 --- a/x-pack/plugins/reporting/server/routes/index.ts +++ b/x-pack/plugins/reporting/server/routes/index.ts @@ -8,8 +8,10 @@ import { LevelLogger as Logger } from '../lib'; import { registerJobGenerationRoutes } from './generation'; import { registerJobInfoRoutes } from './jobs'; import { ReportingCore } from '../core'; +import { registerDiagnosticRoutes } from './diagnostic'; export function registerRoutes(reporting: ReportingCore, logger: Logger) { registerJobGenerationRoutes(reporting, logger); registerJobInfoRoutes(reporting); + registerDiagnosticRoutes(reporting, logger); } diff --git a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts index c508ee6974ca..d1ebb4d59e63 100644 --- a/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts +++ b/x-pack/plugins/reporting/server/test_helpers/create_mock_reportingplugin.ts @@ -8,7 +8,6 @@ jest.mock('../routes'); jest.mock('../usage'); jest.mock('../browsers'); jest.mock('../lib/create_queue'); -jest.mock('../lib/validate'); import * as Rx from 'rxjs'; import { ReportingConfig, ReportingCore } from '../'; diff --git a/x-pack/plugins/reporting/server/test_helpers/index.ts b/x-pack/plugins/reporting/server/test_helpers/index.ts index b37b447dc05a..2d5ef9fdd768 100644 --- a/x-pack/plugins/reporting/server/test_helpers/index.ts +++ b/x-pack/plugins/reporting/server/test_helpers/index.ts @@ -8,3 +8,4 @@ export { createMockServer } from './create_mock_server'; export { createMockReportingCore, createMockConfigSchema } from './create_mock_reportingplugin'; export { createMockBrowserDriverFactory } from './create_mock_browserdriverfactory'; export { createMockLayoutInstance } from './create_mock_layoutinstance'; +export { createMockLevelLogger } from './create_mock_levellogger'; diff --git a/x-pack/plugins/reporting/server/types.ts b/x-pack/plugins/reporting/server/types.ts index 10519842d9de..bb2d5368cd18 100644 --- a/x-pack/plugins/reporting/server/types.ts +++ b/x-pack/plugins/reporting/server/types.ts @@ -160,3 +160,9 @@ export interface ExportTypeDefinition< runTaskFnFactory: RunTaskFnFactory; validLicenses: string[]; } + +export interface DiagnosticResponse { + help: string[]; + success: boolean; + logs: string; +} diff --git a/x-pack/plugins/security/common/licensing/index.mock.ts b/x-pack/plugins/security/common/licensing/index.mock.ts index 06a7057abb87..87225f479cee 100644 --- a/x-pack/plugins/security/common/licensing/index.mock.ts +++ b/x-pack/plugins/security/common/licensing/index.mock.ts @@ -9,6 +9,7 @@ import { SecurityLicense } from '.'; export const licenseMock = { create: (): jest.Mocked => ({ + isLicenseAvailable: jest.fn(), isEnabled: jest.fn().mockReturnValue(true), getFeatures: jest.fn(), features$: of(), diff --git a/x-pack/plugins/security/common/licensing/license_service.test.ts b/x-pack/plugins/security/common/licensing/license_service.test.ts index 564b71a2e0fa..94aad8d3ac53 100644 --- a/x-pack/plugins/security/common/licensing/license_service.test.ts +++ b/x-pack/plugins/security/common/licensing/license_service.test.ts @@ -13,6 +13,7 @@ describe('license features', function () { const serviceSetup = new SecurityLicenseService().setup({ license$: of(undefined as any), }); + expect(serviceSetup.license.isLicenseAvailable()).toEqual(false); expect(serviceSetup.license.getFeatures()).toEqual({ showLogin: true, allowLogin: false, @@ -34,6 +35,7 @@ describe('license features', function () { const serviceSetup = new SecurityLicenseService().setup({ license$: of(rawLicenseMock), }); + expect(serviceSetup.license.isLicenseAvailable()).toEqual(false); expect(serviceSetup.license.getFeatures()).toEqual({ showLogin: true, allowLogin: false, @@ -60,6 +62,7 @@ describe('license features', function () { const subscriptionHandler = jest.fn(); const subscription = serviceSetup.license.features$.subscribe(subscriptionHandler); try { + expect(serviceSetup.license.isLicenseAvailable()).toEqual(false); expect(subscriptionHandler).toHaveBeenCalledTimes(1); expect(subscriptionHandler.mock.calls[0]).toMatchInlineSnapshot(` Array [ @@ -80,6 +83,7 @@ describe('license features', function () { `); rawLicense$.next(licenseMock.createLicenseMock()); + expect(serviceSetup.license.isLicenseAvailable()).toEqual(true); expect(subscriptionHandler).toHaveBeenCalledTimes(2); expect(subscriptionHandler.mock.calls[1]).toMatchInlineSnapshot(` Array [ @@ -112,6 +116,7 @@ describe('license features', function () { const serviceSetup = new SecurityLicenseService().setup({ license$: of(mockRawLicense), }); + expect(serviceSetup.license.isLicenseAvailable()).toEqual(true); expect(serviceSetup.license.getFeatures()).toEqual({ showLogin: true, allowLogin: true, @@ -136,6 +141,7 @@ describe('license features', function () { const serviceSetup = new SecurityLicenseService().setup({ license$: of(mockRawLicense), }); + expect(serviceSetup.license.isLicenseAvailable()).toEqual(true); expect(serviceSetup.license.getFeatures()).toEqual({ showLogin: false, allowLogin: false, @@ -159,6 +165,7 @@ describe('license features', function () { const serviceSetup = new SecurityLicenseService().setup({ license$: of(mockRawLicense), }); + expect(serviceSetup.license.isLicenseAvailable()).toEqual(true); expect(serviceSetup.license.getFeatures()).toEqual({ showLogin: true, allowLogin: true, @@ -182,6 +189,7 @@ describe('license features', function () { const serviceSetup = new SecurityLicenseService().setup({ license$: of(mockRawLicense), }); + expect(serviceSetup.license.isLicenseAvailable()).toEqual(true); expect(serviceSetup.license.getFeatures()).toEqual({ showLogin: true, allowLogin: true, @@ -205,6 +213,7 @@ describe('license features', function () { const serviceSetup = new SecurityLicenseService().setup({ license$: of(mockRawLicense), }); + expect(serviceSetup.license.isLicenseAvailable()).toEqual(true); expect(serviceSetup.license.getFeatures()).toEqual({ showLogin: true, allowLogin: true, diff --git a/x-pack/plugins/security/common/licensing/license_service.ts b/x-pack/plugins/security/common/licensing/license_service.ts index 75c7670f28a6..09b6ae95c282 100644 --- a/x-pack/plugins/security/common/licensing/license_service.ts +++ b/x-pack/plugins/security/common/licensing/license_service.ts @@ -10,6 +10,7 @@ import { ILicense } from '../../../licensing/common/types'; import { SecurityLicenseFeatures } from './license_features'; export interface SecurityLicense { + isLicenseAvailable(): boolean; isEnabled(): boolean; getFeatures(): SecurityLicenseFeatures; features$: Observable; @@ -31,6 +32,8 @@ export class SecurityLicenseService { return { license: Object.freeze({ + isLicenseAvailable: () => rawLicense?.isAvailable ?? false, + isEnabled: () => this.isSecurityEnabledFromRawLicense(rawLicense), getFeatures: () => this.calculateFeaturesFromRawLicense(rawLicense), diff --git a/x-pack/plugins/security/kibana.json b/x-pack/plugins/security/kibana.json index 6a09e9e55a01..40d7e293eaf6 100644 --- a/x-pack/plugins/security/kibana.json +++ b/x-pack/plugins/security/kibana.json @@ -4,7 +4,7 @@ "kibanaVersion": "kibana", "configPath": ["xpack", "security"], "requiredPlugins": ["data", "features", "licensing", "taskManager"], - "optionalPlugins": ["home", "management"], + "optionalPlugins": ["home", "management", "usageCollection"], "server": true, "ui": true, "requiredBundles": [ diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/__snapshots__/elasticsearch_privileges.test.tsx.snap b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/__snapshots__/elasticsearch_privileges.test.tsx.snap index 1c020685c246..a2e46af19bf3 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/__snapshots__/elasticsearch_privileges.test.tsx.snap +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/__snapshots__/elasticsearch_privileges.test.tsx.snap @@ -184,6 +184,7 @@ exports[`it renders without crashing 1`] = ` }, "getFeatures": [MockFunction], "isEnabled": [MockFunction], + "isLicenseAvailable": [MockFunction], } } onChange={[MockFunction]} diff --git a/x-pack/plugins/security/public/plugin.test.tsx b/x-pack/plugins/security/public/plugin.test.tsx index 8cec4fbc2f5a..8fe7d2805e18 100644 --- a/x-pack/plugins/security/public/plugin.test.tsx +++ b/x-pack/plugins/security/public/plugin.test.tsx @@ -41,6 +41,7 @@ describe('Security Plugin', () => { __legacyCompat: { logoutUrl: '/some-base-path/logout', tenant: '/some-base-path' }, authc: { getCurrentUser: expect.any(Function), areAPIKeysEnabled: expect.any(Function) }, license: { + isLicenseAvailable: expect.any(Function), isEnabled: expect.any(Function), getFeatures: expect.any(Function), features$: expect.any(Observable), @@ -67,6 +68,7 @@ describe('Security Plugin', () => { expect(setupManagementServiceMock).toHaveBeenCalledWith({ authc: { getCurrentUser: expect.any(Function), areAPIKeysEnabled: expect.any(Function) }, license: { + isLicenseAvailable: expect.any(Function), isEnabled: expect.any(Function), getFeatures: expect.any(Function), features$: expect.any(Observable), diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts index 636082656f1a..5e9c1818cad2 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.test.ts @@ -74,7 +74,7 @@ describe(`feature_privilege_builder`, () => { Array [ "alerting:1.0.0-zeta1:alert-type/my-feature/get", "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertState", - "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertStatus", + "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertInstanceSummary", "alerting:1.0.0-zeta1:alert-type/my-feature/find", ] `); @@ -111,7 +111,7 @@ describe(`feature_privilege_builder`, () => { Array [ "alerting:1.0.0-zeta1:alert-type/my-feature/get", "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertState", - "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertStatus", + "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertInstanceSummary", "alerting:1.0.0-zeta1:alert-type/my-feature/find", "alerting:1.0.0-zeta1:alert-type/my-feature/create", "alerting:1.0.0-zeta1:alert-type/my-feature/delete", @@ -158,7 +158,7 @@ describe(`feature_privilege_builder`, () => { Array [ "alerting:1.0.0-zeta1:alert-type/my-feature/get", "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertState", - "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertStatus", + "alerting:1.0.0-zeta1:alert-type/my-feature/getAlertInstanceSummary", "alerting:1.0.0-zeta1:alert-type/my-feature/find", "alerting:1.0.0-zeta1:alert-type/my-feature/create", "alerting:1.0.0-zeta1:alert-type/my-feature/delete", @@ -172,7 +172,7 @@ describe(`feature_privilege_builder`, () => { "alerting:1.0.0-zeta1:alert-type/my-feature/unmuteInstance", "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/get", "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/getAlertState", - "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/getAlertStatus", + "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/getAlertInstanceSummary", "alerting:1.0.0-zeta1:readonly-alert-type/my-feature/find", ] `); diff --git a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts index 540b9e5c1e56..eb278a575520 100644 --- a/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts +++ b/x-pack/plugins/security/server/authorization/privileges/feature_privilege_builder/alerting.ts @@ -8,7 +8,7 @@ import { uniq } from 'lodash'; import { Feature, FeatureKibanaPrivileges } from '../../../../../features/server'; import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder'; -const readOperations: string[] = ['get', 'getAlertState', 'getAlertStatus', 'find']; +const readOperations: string[] = ['get', 'getAlertState', 'getAlertInstanceSummary', 'find']; const writeOperations: string[] = [ 'create', 'delete', diff --git a/x-pack/plugins/security/server/config.test.ts b/x-pack/plugins/security/server/config.test.ts index 520081ae30d8..093a7643fbf6 100644 --- a/x-pack/plugins/security/server/config.test.ts +++ b/x-pack/plugins/security/server/config.test.ts @@ -904,11 +904,13 @@ describe('createConfig()', () => { }, "sortedProviders": Array [ Object { + "hasAccessAgreement": false, "name": "saml", "order": 0, "type": "saml", }, Object { + "hasAccessAgreement": false, "name": "basic", "order": 1, "type": "basic", @@ -982,6 +984,63 @@ describe('createConfig()', () => { ).toBe(true); }); + it('indicates which providers have the access agreement enabled', () => { + expect( + createConfig( + ConfigSchema.validate({ + authc: { + providers: { + basic: { basic1: { order: 3 } }, + saml: { + saml1: { order: 2, realm: 'saml1', accessAgreement: { message: 'foo' } }, + saml2: { order: 1, realm: 'saml2' }, + }, + oidc: { + oidc1: { order: 0, realm: 'oidc1', accessAgreement: { message: 'foo' } }, + oidc2: { order: 4, realm: 'oidc2' }, + }, + }, + }, + }), + loggingSystemMock.create().get(), + { isTLSEnabled: true } + ).authc.sortedProviders + ).toMatchInlineSnapshot(` + Array [ + Object { + "hasAccessAgreement": true, + "name": "oidc1", + "order": 0, + "type": "oidc", + }, + Object { + "hasAccessAgreement": false, + "name": "saml2", + "order": 1, + "type": "saml", + }, + Object { + "hasAccessAgreement": true, + "name": "saml1", + "order": 2, + "type": "saml", + }, + Object { + "hasAccessAgreement": false, + "name": "basic1", + "order": 3, + "type": "basic", + }, + Object { + "hasAccessAgreement": false, + "name": "oidc2", + "order": 4, + "type": "oidc", + }, + ] + `); + }); + it('correctly sorts providers based on the `order`', () => { expect( createConfig( @@ -1000,26 +1059,31 @@ describe('createConfig()', () => { ).toMatchInlineSnapshot(` Array [ Object { + "hasAccessAgreement": false, "name": "oidc1", "order": 0, "type": "oidc", }, Object { + "hasAccessAgreement": false, "name": "saml2", "order": 1, "type": "saml", }, Object { + "hasAccessAgreement": false, "name": "saml1", "order": 2, "type": "saml", }, Object { + "hasAccessAgreement": false, "name": "basic1", "order": 3, "type": "basic", }, Object { + "hasAccessAgreement": false, "name": "oidc2", "order": 4, "type": "oidc", diff --git a/x-pack/plugins/security/server/config.ts b/x-pack/plugins/security/server/config.ts index dcfe4825fb03..9ccbdac5e09f 100644 --- a/x-pack/plugins/security/server/config.ts +++ b/x-pack/plugins/security/server/config.ts @@ -255,13 +255,19 @@ export function createConfig( type: keyof ProvidersConfigType; name: string; order: number; + hasAccessAgreement: boolean; }> = []; for (const [type, providerGroup] of Object.entries(providers)) { - for (const [name, { enabled, order }] of Object.entries(providerGroup ?? {})) { + for (const [name, { enabled, order, accessAgreement }] of Object.entries(providerGroup ?? {})) { if (!enabled) { delete providerGroup![name]; } else { - sortedProviders.push({ type: type as any, name, order }); + sortedProviders.push({ + type: type as any, + name, + order, + hasAccessAgreement: !!accessAgreement?.message, + }); } } } diff --git a/x-pack/plugins/security/server/plugin.test.ts b/x-pack/plugins/security/server/plugin.test.ts index 8d13f8107571..9825e77b164c 100644 --- a/x-pack/plugins/security/server/plugin.test.ts +++ b/x-pack/plugins/security/server/plugin.test.ts @@ -108,6 +108,7 @@ describe('Security Plugin', () => { }, "getFeatures": [Function], "isEnabled": [Function], + "isLicenseAvailable": [Function], }, "registerSpacesService": [Function], } diff --git a/x-pack/plugins/security/server/plugin.ts b/x-pack/plugins/security/server/plugin.ts index 7d94e03916fa..1eb406dd2061 100644 --- a/x-pack/plugins/security/server/plugin.ts +++ b/x-pack/plugins/security/server/plugin.ts @@ -7,6 +7,7 @@ import { combineLatest } from 'rxjs'; import { first, map } from 'rxjs/operators'; import { TypeOf } from '@kbn/config-schema'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { deepFreeze, CoreSetup, @@ -32,6 +33,7 @@ import { AuditService, SecurityAuditLogger, AuditServiceSetup } from './audit'; import { SecurityFeatureUsageService, SecurityFeatureUsageServiceStart } from './feature_usage'; import { ElasticsearchService } from './elasticsearch'; import { SessionManagementService } from './session_management'; +import { registerSecurityUsageCollector } from './usage_collector'; export type SpacesService = Pick< SpacesPluginSetup['spacesService'], @@ -74,6 +76,7 @@ export interface PluginSetupDependencies { features: FeaturesPluginSetup; licensing: LicensingPluginSetup; taskManager: TaskManagerSetupContract; + usageCollection?: UsageCollectionSetup; } export interface PluginStartDependencies { @@ -123,7 +126,7 @@ export class Plugin { public async setup( core: CoreSetup, - { features, licensing, taskManager }: PluginSetupDependencies + { features, licensing, taskManager, usageCollection }: PluginSetupDependencies ) { const [config, legacyConfig] = await combineLatest([ this.initializerContext.config.create>().pipe( @@ -151,6 +154,8 @@ export class Plugin { this.featureUsageService.setup({ featureUsage: licensing.featureUsage }); + registerSecurityUsageCollector({ usageCollection, config, license }); + const audit = this.auditService.setup({ license, config: config.audit }); const auditLogger = new SecurityAuditLogger(audit.getLogger()); diff --git a/x-pack/plugins/security/server/usage_collector/index.ts b/x-pack/plugins/security/server/usage_collector/index.ts new file mode 100644 index 000000000000..dd405ebac424 --- /dev/null +++ b/x-pack/plugins/security/server/usage_collector/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { registerSecurityUsageCollector } from './security_usage_collector'; diff --git a/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts b/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts new file mode 100644 index 000000000000..6c3dcddcdb41 --- /dev/null +++ b/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts @@ -0,0 +1,465 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { createConfig, ConfigSchema } from '../config'; +import { loggingSystemMock } from 'src/core/server/mocks'; +import { TypeOf } from '@kbn/config-schema'; +import { usageCollectionPluginMock } from 'src/plugins/usage_collection/server/mocks'; +import { registerSecurityUsageCollector } from './security_usage_collector'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; +import { licenseMock } from '../../common/licensing/index.mock'; +import { SecurityLicenseFeatures } from '../../common/licensing'; + +describe('Security UsageCollector', () => { + const createSecurityConfig = (config: TypeOf) => { + return createConfig(config, loggingSystemMock.createLogger(), { isTLSEnabled: true }); + }; + + const createSecurityLicense = ({ + allowAccessAgreement = true, + allowAuditLogging = true, + allowRbac = true, + isLicenseAvailable, + }: Partial & { isLicenseAvailable: boolean }) => { + const license = licenseMock.create(); + license.isLicenseAvailable.mockReturnValue(isLicenseAvailable); + license.getFeatures.mockReturnValue({ + allowAccessAgreement, + allowAuditLogging, + allowRbac, + } as SecurityLicenseFeatures); + return license; + }; + + const clusterClient = elasticsearchServiceMock.createLegacyClusterClient(); + + describe('initialization', () => { + it('handles an undefined usage collector', () => { + const config = createSecurityConfig(ConfigSchema.validate({})); + const usageCollection = undefined; + const license = createSecurityLicense({ allowRbac: false, isLicenseAvailable: false }); + registerSecurityUsageCollector({ usageCollection, config, license }); + }); + + it('registers itself and waits for the license to become available before reporting itself as ready', async () => { + const config = createSecurityConfig(ConfigSchema.validate({})); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ allowRbac: false, isLicenseAvailable: false }); + + registerSecurityUsageCollector({ usageCollection, config, license }); + + expect(usageCollection.getCollectorByType('security')?.isReady()).toBe(false); + + license.isLicenseAvailable.mockReturnValue(true); + license.getFeatures.mockReturnValue({ allowRbac: true } as SecurityLicenseFeatures); + + expect(usageCollection.getCollectorByType('security')?.isReady()).toBe(true); + }); + }); + + it('reports correctly for a default configuration', async () => { + const config = createSecurityConfig(ConfigSchema.validate({})); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ isLicenseAvailable: true }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(clusterClient.asScoped().callAsCurrentUser); + + expect(usage).toEqual({ + auditLoggingEnabled: false, + accessAgreementEnabled: false, + authProviderCount: 1, + enabledAuthProviders: ['basic'], + loginSelectorEnabled: false, + httpAuthSchemes: ['apikey'], + }); + }); + + it('reports correctly when security is disabled in Elasticsearch', async () => { + const config = createSecurityConfig(ConfigSchema.validate({})); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ allowRbac: false, isLicenseAvailable: true }); + + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(clusterClient.asScoped().callAsCurrentUser); + + expect(usage).toEqual({ + auditLoggingEnabled: false, + accessAgreementEnabled: false, + authProviderCount: 0, + enabledAuthProviders: [], + loginSelectorEnabled: false, + httpAuthSchemes: [], + }); + }); + + describe('auth providers', () => { + it('does not report disabled auth providers', async () => { + const config = createSecurityConfig( + ConfigSchema.validate({ + authc: { + providers: { + basic: { + basic: { + order: 0, + }, + disabledBasic: { + enabled: false, + order: 1, + }, + }, + saml: { + disabledSaml: { + enabled: false, + realm: 'foo', + order: 2, + }, + }, + }, + }, + }) + ); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ isLicenseAvailable: true }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(clusterClient.asScoped().callAsCurrentUser); + + expect(usage).toEqual({ + auditLoggingEnabled: false, + accessAgreementEnabled: false, + authProviderCount: 1, + enabledAuthProviders: ['basic'], + loginSelectorEnabled: false, + httpAuthSchemes: ['apikey'], + }); + }); + + it('reports the types and count of enabled auth providers', async () => { + const config = createSecurityConfig( + ConfigSchema.validate({ + authc: { + providers: { + basic: { + basic: { + order: 0, + enabled: false, + }, + }, + saml: { + saml1: { + realm: 'foo', + order: 1, + }, + saml2: { + realm: 'bar', + order: 2, + }, + }, + pki: { + pki1: { + enabled: true, + order: 3, + }, + }, + }, + }, + }) + ); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ isLicenseAvailable: true }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(clusterClient.asScoped().callAsCurrentUser); + + expect(usage).toEqual({ + auditLoggingEnabled: false, + accessAgreementEnabled: false, + authProviderCount: 3, + enabledAuthProviders: ['saml', 'pki'], + loginSelectorEnabled: true, + httpAuthSchemes: ['apikey'], + }); + }); + }); + + describe('access agreement', () => { + it('reports if the access agreement message is configured for any provider', async () => { + const config = createSecurityConfig( + ConfigSchema.validate({ + authc: { + providers: { + saml: { + saml1: { + realm: 'foo', + order: 1, + accessAgreement: { + message: 'foo message', + }, + }, + }, + }, + }, + }) + ); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ isLicenseAvailable: true }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(clusterClient.asScoped().callAsCurrentUser); + + expect(usage).toEqual({ + auditLoggingEnabled: false, + accessAgreementEnabled: true, + authProviderCount: 1, + enabledAuthProviders: ['saml'], + loginSelectorEnabled: false, + httpAuthSchemes: ['apikey'], + }); + }); + it('does not report the access agreement if the license does not permit it', async () => { + const config = createSecurityConfig( + ConfigSchema.validate({ + authc: { + providers: { + saml: { + saml1: { + realm: 'foo', + order: 1, + accessAgreement: { + message: 'foo message', + }, + }, + }, + }, + }, + }) + ); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ + isLicenseAvailable: true, + allowAccessAgreement: false, + }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(clusterClient.asScoped().callAsCurrentUser); + + expect(usage).toEqual({ + auditLoggingEnabled: false, + accessAgreementEnabled: false, + authProviderCount: 1, + enabledAuthProviders: ['saml'], + loginSelectorEnabled: false, + httpAuthSchemes: ['apikey'], + }); + }); + + it('does not report the access agreement for disabled providers', async () => { + const config = createSecurityConfig( + ConfigSchema.validate({ + authc: { + providers: { + saml: { + saml1: { + enabled: false, + realm: 'foo', + order: 1, + accessAgreement: { + message: 'foo message', + }, + }, + saml2: { + realm: 'foo', + order: 2, + }, + }, + }, + }, + }) + ); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ isLicenseAvailable: true }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(clusterClient.asScoped().callAsCurrentUser); + + expect(usage).toEqual({ + auditLoggingEnabled: false, + accessAgreementEnabled: false, + authProviderCount: 1, + enabledAuthProviders: ['saml'], + loginSelectorEnabled: false, + httpAuthSchemes: ['apikey'], + }); + }); + }); + + describe('login selector', () => { + it('reports when the login selector is enabled', async () => { + const config = createSecurityConfig( + ConfigSchema.validate({ + authc: { + selector: { + enabled: true, + }, + providers: { + saml: { + saml1: { + realm: 'foo', + order: 1, + showInSelector: true, + }, + }, + }, + }, + }) + ); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ isLicenseAvailable: true }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(clusterClient.asScoped().callAsCurrentUser); + + expect(usage).toEqual({ + auditLoggingEnabled: false, + accessAgreementEnabled: false, + authProviderCount: 1, + enabledAuthProviders: ['saml'], + loginSelectorEnabled: true, + httpAuthSchemes: ['apikey'], + }); + }); + }); + + describe('audit logging', () => { + it('reports when audit logging is enabled', async () => { + const config = createSecurityConfig( + ConfigSchema.validate({ + audit: { + enabled: true, + }, + }) + ); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ isLicenseAvailable: true, allowAuditLogging: true }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(clusterClient.asScoped().callAsCurrentUser); + + expect(usage).toEqual({ + auditLoggingEnabled: true, + accessAgreementEnabled: false, + authProviderCount: 1, + enabledAuthProviders: ['basic'], + loginSelectorEnabled: false, + httpAuthSchemes: ['apikey'], + }); + }); + + it('does not report audit logging when the license does not permit it', async () => { + const config = createSecurityConfig( + ConfigSchema.validate({ + audit: { + enabled: true, + }, + }) + ); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ isLicenseAvailable: true, allowAuditLogging: false }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(clusterClient.asScoped().callAsCurrentUser); + + expect(usage).toEqual({ + auditLoggingEnabled: false, + accessAgreementEnabled: false, + authProviderCount: 1, + enabledAuthProviders: ['basic'], + loginSelectorEnabled: false, + httpAuthSchemes: ['apikey'], + }); + }); + }); + + describe('http auth schemes', () => { + it('reports customized http auth schemes', async () => { + const config = createSecurityConfig( + ConfigSchema.validate({ + authc: { + http: { + schemes: ['basic', 'Negotiate'], + }, + }, + }) + ); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ isLicenseAvailable: true, allowAuditLogging: false }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(clusterClient.asScoped().callAsCurrentUser); + + expect(usage).toEqual({ + auditLoggingEnabled: false, + accessAgreementEnabled: false, + authProviderCount: 1, + enabledAuthProviders: ['basic'], + loginSelectorEnabled: false, + httpAuthSchemes: ['basic', 'Negotiate'], + }); + }); + + it('does not report auth schemes that are not "well known"', async () => { + const config = createSecurityConfig( + ConfigSchema.validate({ + authc: { + http: { + schemes: ['basic', 'Negotiate', 'customScheme'], + }, + }, + }) + ); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ isLicenseAvailable: true, allowAuditLogging: false }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(clusterClient.asScoped().callAsCurrentUser); + + expect(usage).toEqual({ + auditLoggingEnabled: false, + accessAgreementEnabled: false, + authProviderCount: 1, + enabledAuthProviders: ['basic'], + loginSelectorEnabled: false, + httpAuthSchemes: ['basic', 'Negotiate'], + }); + }); + }); +}); diff --git a/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts b/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts new file mode 100644 index 000000000000..11e58f7f95fc --- /dev/null +++ b/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; +import { ConfigType } from '../config'; +import { SecurityLicense } from '../../common/licensing'; + +interface Usage { + auditLoggingEnabled: boolean; + loginSelectorEnabled: boolean; + accessAgreementEnabled: boolean; + authProviderCount: number; + enabledAuthProviders: string[]; + httpAuthSchemes: string[]; +} + +interface Deps { + usageCollection?: UsageCollectionSetup; + config: ConfigType; + license: SecurityLicense; +} + +// List of auth schemes collected from https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml +const WELL_KNOWN_AUTH_SCHEMES = [ + 'basic', + 'bearer', + 'digest', + 'hoba', + 'mutual', + 'negotiate', + 'oauth', + 'scram-sha-1', + 'scram-sha-256', + 'vapid', + 'apikey', // not part of the spec, but used by the Elastic Stack for API Key authentication +]; + +export function registerSecurityUsageCollector({ usageCollection, config, license }: Deps): void { + // usageCollection is an optional dependency, so make sure to return if it is not registered. + if (!usageCollection) { + return; + } + + // create usage collector + const securityCollector = usageCollection.makeUsageCollector({ + type: 'security', + isReady: () => license.isLicenseAvailable(), + schema: { + auditLoggingEnabled: { + type: 'boolean', + }, + loginSelectorEnabled: { + type: 'boolean', + }, + accessAgreementEnabled: { + type: 'boolean', + }, + authProviderCount: { + type: 'number', + }, + enabledAuthProviders: { + type: 'keyword', + }, + httpAuthSchemes: { + type: 'keyword', + }, + }, + fetch: () => { + const { allowRbac, allowAccessAgreement, allowAuditLogging } = license.getFeatures(); + if (!allowRbac) { + return { + auditLoggingEnabled: false, + loginSelectorEnabled: false, + accessAgreementEnabled: false, + authProviderCount: 0, + enabledAuthProviders: [], + httpAuthSchemes: [], + }; + } + + const auditLoggingEnabled = allowAuditLogging && config.audit.enabled; + const loginSelectorEnabled = config.authc.selector.enabled; + const authProviderCount = config.authc.sortedProviders.length; + const enabledAuthProviders = [ + ...new Set( + config.authc.sortedProviders.reduce( + (acc, provider) => [...acc, provider.type], + [] as string[] + ) + ), + ]; + const accessAgreementEnabled = + allowAccessAgreement && + config.authc.sortedProviders.some((provider) => provider.hasAccessAgreement); + + const httpAuthSchemes = config.authc.http.schemes.filter((scheme) => + WELL_KNOWN_AUTH_SCHEMES.includes(scheme.toLowerCase()) + ); + + return { + auditLoggingEnabled, + loginSelectorEnabled, + accessAgreementEnabled, + authProviderCount, + enabledAuthProviders, + httpAuthSchemes, + }; + }, + }); + + // register usage collector + usageCollection.registerCollector(securityCollector); +} diff --git a/x-pack/plugins/security_solution/common/endpoint/constants.ts b/x-pack/plugins/security_solution/common/endpoint/constants.ts index 366bf7a1df1f..a6018837fa4f 100644 --- a/x-pack/plugins/security_solution/common/endpoint/constants.ts +++ b/x-pack/plugins/security_solution/common/endpoint/constants.ts @@ -7,6 +7,7 @@ export const eventsIndexPattern = 'logs-endpoint.events.*'; export const alertsIndexPattern = 'logs-endpoint.alerts-*'; export const metadataIndexPattern = 'metrics-endpoint.metadata-*'; +export const metadataCurrentIndexPattern = 'metrics-endpoint.metadata_current-*'; export const policyIndexPattern = 'metrics-endpoint.policy-*'; export const telemetryIndexPattern = 'metrics-endpoint.telemetry-*'; export const LIMITED_CONCURRENCY_ENDPOINT_ROUTE_TAG = 'endpoint:limited-concurrency'; diff --git a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts index 0955f196df17..e1ff34463d21 100644 --- a/x-pack/plugins/security_solution/common/endpoint/generate_data.ts +++ b/x-pack/plugins/security_solution/common/endpoint/generate_data.ts @@ -1132,7 +1132,8 @@ export class EndpointDocGenerator { path: '/package/endpoint/0.5.0', icons: [ { - src: '/package/endpoint/0.5.0/img/logo-endpoint-64-color.svg', + path: '/package/endpoint/0.5.0/img/logo-endpoint-64-color.svg', + src: '/img/logo-endpoint-64-color.svg', size: '16x16', type: 'image/svg+xml', }, diff --git a/x-pack/plugins/security_solution/common/endpoint/types/index.ts b/x-pack/plugins/security_solution/common/endpoint/types/index.ts index 8e507cbc921a..e0bd916103a2 100644 --- a/x-pack/plugins/security_solution/common/endpoint/types/index.ts +++ b/x-pack/plugins/security_solution/common/endpoint/types/index.ts @@ -445,6 +445,13 @@ export type HostInfo = Immutable<{ host_status: HostStatus; }>; +export type HostMetadataDetails = Immutable<{ + agent: { + id: string; + }; + HostDetails: HostMetadata; +}>; + export type HostMetadata = Immutable<{ '@timestamp': number; event: { diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts index b7d905d22e83..35fcc3b07fd0 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/index.ts @@ -23,6 +23,8 @@ import { } from './hosts'; import { NetworkQueries, + NetworkDetailsStrategyResponse, + NetworkDetailsRequestOptions, NetworkDnsStrategyResponse, NetworkDnsRequestOptions, NetworkTlsStrategyResponse, @@ -35,6 +37,8 @@ import { NetworkTopCountriesRequestOptions, NetworkTopNFlowStrategyResponse, NetworkTopNFlowRequestOptions, + NetworkUsersStrategyResponse, + NetworkUsersRequestOptions, } from './network'; import { MatrixHistogramQuery, @@ -87,6 +91,8 @@ export type StrategyResponseType = T extends HostsQ ? HostFirstLastSeenStrategyResponse : T extends HostsQueries.uncommonProcesses ? HostUncommonProcessesStrategyResponse + : T extends NetworkQueries.details + ? NetworkDetailsStrategyResponse : T extends NetworkQueries.dns ? NetworkDnsStrategyResponse : T extends NetworkQueries.http @@ -99,6 +105,8 @@ export type StrategyResponseType = T extends HostsQ ? NetworkTopCountriesStrategyResponse : T extends NetworkQueries.topNFlow ? NetworkTopNFlowStrategyResponse + : T extends NetworkQueries.users + ? NetworkUsersStrategyResponse : T extends typeof MatrixHistogramQuery ? MatrixHistogramStrategyResponse : never; @@ -115,6 +123,8 @@ export type StrategyRequestType = T extends HostsQu ? HostFirstLastSeenRequestOptions : T extends HostsQueries.uncommonProcesses ? HostUncommonProcessesRequestOptions + : T extends NetworkQueries.details + ? NetworkDetailsRequestOptions : T extends NetworkQueries.dns ? NetworkDnsRequestOptions : T extends NetworkQueries.http @@ -127,6 +137,8 @@ export type StrategyRequestType = T extends HostsQu ? NetworkTopCountriesRequestOptions : T extends NetworkQueries.topNFlow ? NetworkTopNFlowRequestOptions + : T extends NetworkQueries.users + ? NetworkUsersRequestOptions : T extends typeof MatrixHistogramQuery ? MatrixHistogramRequestOptions : never; diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/common/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/common/index.ts index 66676569b3c9..19521741c5f6 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/common/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/common/index.ts @@ -15,6 +15,13 @@ export enum NetworkTopTablesFields { source_ips = 'source_ips', } +export enum FlowTarget { + client = 'client', + destination = 'destination', + server = 'server', + source = 'source', +} + export enum FlowTargetSourceDest { destination = 'destination', source = 'source', diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/details/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/details/index.ts new file mode 100644 index 000000000000..920d7cf8c5ea --- /dev/null +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/details/index.ts @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IEsSearchResponse } from '../../../../../../../../src/plugins/data/common'; +import { HostEcs } from '../../../../ecs/host'; +import { GeoEcs } from '../../../../ecs/geo'; +import { Inspect, Maybe, TotalValue, Hit, ShardsResponse } from '../../../common'; +import { RequestBasicOptions } from '../..'; + +export interface NetworkDetailsRequestOptions extends Omit { + ip: string; +} + +export interface NetworkDetailsStrategyResponse extends IEsSearchResponse { + networkDetails: { + client?: Maybe; + destination?: Maybe; + host?: HostEcs; + server?: Maybe; + source?: Maybe; + }; + inspect?: Maybe; +} + +export interface NetworkDetails { + firstSeen?: Maybe; + lastSeen?: Maybe; + autonomousSystem: AutonomousSystem; + geo: GeoEcs; +} + +export interface AutonomousSystem { + number?: Maybe; + organization?: Maybe; +} + +export interface AutonomousSystemOrganization { + name?: Maybe; +} + +interface ResultHit { + doc_count: number; + results: { + hits: { + total: TotalValue | number; + max_score: number | null; + hits: Array<{ + _source: T; + sort?: [number]; + _index?: string; + _type?: string; + _id?: string; + _score?: number | null; + }>; + }; + }; +} + +export interface NetworkHit { + took?: number; + timed_out?: boolean; + _scroll_id?: string; + _shards?: ShardsResponse; + timeout?: number; + hits?: { + total: number; + hits: Hit[]; + }; + doc_count: number; + geo: ResultHit; + autonomousSystem: ResultHit; + firstSeen: { + value: number; + value_as_string: string; + }; + lastSeen: { + value: number; + value_as_string: string; + }; +} + +export type NetworkDetailsHostHit = ResultHit; + +export interface NetworkDetailsHit { + aggregations: { + destination?: NetworkHit; + source?: NetworkHit; + host: ResultHit; + }; + _shards: { + total: number; + successful: number; + skipped: number; + failed: number; + }; + hits: { + total: { + value: number; + relation: string; + }; + max_score: number | null; + hits: []; + }; + took: number; + timeout: number; +} diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/http/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/http/index.ts index ad58442b1699..cd661cd9b9e9 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/http/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/http/index.ts @@ -8,6 +8,16 @@ import { IEsSearchResponse } from '../../../../../../../../src/plugins/data/comm import { Maybe, CursorType, Inspect, PageInfoPaginated, GenericBuckets } from '../../../common'; import { RequestOptionsPaginated } from '../..'; +export enum NetworkHttpFields { + domains = 'domains', + lastHost = 'lastHost', + lastSourceIp = 'lastSourceIp', + methods = 'methods', + path = 'path', + requestCount = 'requestCount', + statuses = 'statuses', +} + export interface NetworkHttpRequestOptions extends RequestOptionsPaginated { ip?: string; defaultIndex: string[]; diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/index.ts index d61acbe62ffb..4e73fe11ef43 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/index.ts @@ -5,18 +5,22 @@ */ export * from './common'; +export * from './details'; export * from './dns'; export * from './http'; export * from './overview'; export * from './tls'; export * from './top_countries'; export * from './top_n_flow'; +export * from './users'; export enum NetworkQueries { + details = 'networkDetails', dns = 'dns', http = 'http', overview = 'overviewNetwork', tls = 'tls', topCountries = 'topCountries', topNFlow = 'topNFlow', + users = 'users', } diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/tls/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/tls/index.ts index dffc994fcf4c..5e1c9459aaac 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/tls/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/tls/index.ts @@ -9,7 +9,7 @@ import { CursorType, Inspect, Maybe, PageInfoPaginated } from '../../../common'; import { RequestOptionsPaginated } from '../..'; import { FlowTargetSourceDest } from '../common'; -export interface TlsBuckets { +export interface NetworkTlsBuckets { key: string; timestamp?: { value: number; @@ -29,7 +29,7 @@ export interface TlsBuckets { }; } -export interface TlsNode { +export interface NetworkTlsNode { _id?: Maybe; timestamp?: Maybe; notAfter?: Maybe; @@ -38,23 +38,23 @@ export interface TlsNode { issuers?: Maybe; } -export enum TlsFields { +export enum NetworkTlsFields { _id = '_id', } -export interface TlsEdges { - node: TlsNode; +export interface NetworkTlsEdges { + node: NetworkTlsNode; cursor: CursorType; } -export interface NetworkTlsRequestOptions extends RequestOptionsPaginated { +export interface NetworkTlsRequestOptions extends RequestOptionsPaginated { ip: string; flowTarget: FlowTargetSourceDest; defaultIndex: string[]; } export interface NetworkTlsStrategyResponse extends IEsSearchResponse { - edges: TlsEdges[]; + edges: NetworkTlsEdges[]; totalCount: number; pageInfo: PageInfoPaginated; inspect?: Maybe; diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/top_countries/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/top_countries/index.ts index a28388a2c6f8..2c89bbf048e6 100644 --- a/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/top_countries/index.ts +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/top_countries/index.ts @@ -14,13 +14,6 @@ import { TopNetworkTablesEcsField, } from '../common'; -export enum FlowTarget { - client = 'client', - destination = 'destination', - server = 'server', - source = 'source', -} - export interface TopCountriesItemSource { country?: Maybe; destination_ips?: Maybe; diff --git a/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/users/index.ts b/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/users/index.ts new file mode 100644 index 000000000000..196317e7587b --- /dev/null +++ b/x-pack/plugins/security_solution/common/search_strategy/security_solution/network/users/index.ts @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IEsSearchResponse } from '../../../../../../../../src/plugins/data/common'; +import { CursorType, Inspect, Maybe, PageInfoPaginated, SortField } from '../../../common'; +import { FlowTarget } from '../common'; +import { RequestOptionsPaginated } from '../..'; + +export enum NetworkUsersFields { + name = 'name', + count = 'count', +} + +export interface NetworkUsersRequestOptions extends RequestOptionsPaginated { + ip: string; + sort: SortField; + flowTarget: FlowTarget; +} + +export interface NetworkUsersStrategyResponse extends IEsSearchResponse { + edges: NetworkUsersEdges[]; + totalCount: number; + pageInfo: PageInfoPaginated; + inspect?: Maybe; +} + +export interface NetworkUsersEdges { + node: NetworkUsersNode; + cursor: CursorType; +} + +export interface NetworkUsersNode { + _id?: Maybe; + timestamp?: Maybe; + user?: Maybe; +} + +export interface NetworkUsersItem { + name?: Maybe; + id?: Maybe; + groupId?: Maybe; + groupName?: Maybe; + count?: Maybe; +} + +export interface NetworkUsersBucketsItem { + key: string; + doc_count: number; + groupName?: NetworkUsersGroupName; + groupId?: NetworkUsersGroupId; + id?: Id; +} + +export interface NetworkUsersGroupName { + doc_count_error_upper_bound: number; + sum_other_doc_count: number; + buckets: NetworkUsersBucketsItem[]; +} + +export interface NetworkUsersGroupId { + doc_count_error_upper_bound: number; + sum_other_doc_count: number; + buckets: NetworkUsersBucketsItem[]; +} + +interface Id { + doc_count_error_upper_bound: number; + sum_other_doc_count: number; + buckets: NetworkUsersBucketsItem[]; +} diff --git a/x-pack/plugins/security_solution/cypress/integration/url_compatibility.spec.ts b/x-pack/plugins/security_solution/cypress/integration/url_compatibility.spec.ts index d55a8faae021..5b42897b065e 100644 --- a/x-pack/plugins/security_solution/cypress/integration/url_compatibility.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/url_compatibility.spec.ts @@ -18,8 +18,7 @@ const ABSOLUTE_DATE = { startTime: '2019-08-01T20:03:29.186Z', }; -// FLAKY: https://github.com/elastic/kibana/issues/75697 -describe.skip('URL compatibility', () => { +describe('URL compatibility', () => { it('Redirects to Detection alerts from old Detections URL', () => { loginAndWaitForPage(DETECTIONS); diff --git a/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts b/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts index 79756621ef50..5ec5bb97250d 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts @@ -80,9 +80,9 @@ export const selectNumberOfRules = (numberOfRules: number) => { }; export const sortByActivatedRules = () => { - cy.get(SORT_RULES_BTN).click({ force: true }); + cy.get(SORT_RULES_BTN).contains('Activated').click({ force: true }); waitForRulesToBeLoaded(); - cy.get(SORT_RULES_BTN).click({ force: true }); + cy.get(SORT_RULES_BTN).contains('Activated').click({ force: true }); waitForRulesToBeLoaded(); }; diff --git a/x-pack/plugins/security_solution/public/common/components/link_to/__mocks__/index.ts b/x-pack/plugins/security_solution/public/common/components/link_to/__mocks__/index.ts index 6c9620e27fab..07855c347710 100644 --- a/x-pack/plugins/security_solution/public/common/components/link_to/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/public/common/components/link_to/__mocks__/index.ts @@ -9,7 +9,7 @@ import { SecurityPageName } from '../../../../app/types'; export { getDetectionEngineUrl } from '../redirect_to_detection_engine'; export { getAppOverviewUrl } from '../redirect_to_overview'; export { getHostDetailsUrl, getHostsUrl } from '../redirect_to_hosts'; -export { getNetworkUrl, getIPDetailsUrl } from '../redirect_to_network'; +export { getNetworkUrl, getNetworkDetailsUrl } from '../redirect_to_network'; export { getTimelinesUrl, getTimelineTabsUrl } from '../redirect_to_timelines'; export { getCaseDetailsUrl, diff --git a/x-pack/plugins/security_solution/public/common/components/link_to/index.ts b/x-pack/plugins/security_solution/public/common/components/link_to/index.ts index c6e58d420695..403c8d838fa4 100644 --- a/x-pack/plugins/security_solution/public/common/components/link_to/index.ts +++ b/x-pack/plugins/security_solution/public/common/components/link_to/index.ts @@ -15,7 +15,7 @@ import { useKibana } from '../../lib/kibana'; export { getDetectionEngineUrl } from './redirect_to_detection_engine'; export { getAppOverviewUrl } from './redirect_to_overview'; export { getHostDetailsUrl, getHostsUrl } from './redirect_to_hosts'; -export { getNetworkUrl, getIPDetailsUrl } from './redirect_to_network'; +export { getNetworkUrl, getNetworkDetailsUrl } from './redirect_to_network'; export { getTimelinesUrl, getTimelineTabsUrl } from './redirect_to_timelines'; export { getCaseDetailsUrl, diff --git a/x-pack/plugins/security_solution/public/common/components/link_to/redirect_to_network.tsx b/x-pack/plugins/security_solution/public/common/components/link_to/redirect_to_network.tsx index 100c5e46141a..c042c8e1470b 100644 --- a/x-pack/plugins/security_solution/public/common/components/link_to/redirect_to_network.tsx +++ b/x-pack/plugins/security_solution/public/common/components/link_to/redirect_to_network.tsx @@ -13,7 +13,7 @@ import { appendSearch } from './helpers'; export const getNetworkUrl = (search?: string) => `${appendSearch(search)}`; -export const getIPDetailsUrl = ( +export const getNetworkDetailsUrl = ( detailName: string, flowTarget?: FlowTarget | FlowTargetSourceDest, search?: string diff --git a/x-pack/plugins/security_solution/public/common/components/links/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/links/index.test.tsx index b6817c4cab1f..e6d34b5e432a 100644 --- a/x-pack/plugins/security_solution/public/common/components/links/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/links/index.test.tsx @@ -14,7 +14,7 @@ import { useUiSetting$ } from '../../lib/kibana'; import { GoogleLink, HostDetailsLink, - IPDetailsLink, + NetworkDetailsLink, ReputationLink, WhoIsLink, CertificateFingerprintLink, @@ -61,9 +61,9 @@ describe('Custom Links', () => { }); }); - describe('IPDetailsLink', () => { + describe('NetworkDetailsLink', () => { test('should render valid link to IP Details with ipv4 as the display text', () => { - const wrapper = mount(); + const wrapper = mount(); expect(wrapper.find('EuiLink').prop('href')).toEqual( `/ip/${encodeURIComponent(ipv4)}/source` ); @@ -71,7 +71,7 @@ describe('Custom Links', () => { }); test('should render valid link to IP Details with child text as the display text', () => { - const wrapper = mount({hostName}); + const wrapper = mount({hostName}); expect(wrapper.find('EuiLink').prop('href')).toEqual( `/ip/${encodeURIComponent(ipv4)}/source` ); @@ -79,7 +79,7 @@ describe('Custom Links', () => { }); test('should render valid link to IP Details with ipv6 as the display text', () => { - const wrapper = mount(); + const wrapper = mount(); expect(wrapper.find('EuiLink').prop('href')).toEqual( `/ip/${encodeURIComponent(ipv6Encoded)}/source` ); diff --git a/x-pack/plugins/security_solution/public/common/components/links/index.tsx b/x-pack/plugins/security_solution/public/common/components/links/index.tsx index 943f2d8336ca..d6cbd31e86dd 100644 --- a/x-pack/plugins/security_solution/public/common/components/links/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/links/index.tsx @@ -28,7 +28,7 @@ import { encodeIpv6 } from '../../lib/helpers'; import { getCaseDetailsUrl, getHostDetailsUrl, - getIPDetailsUrl, + getNetworkDetailsUrl, getCreateCaseUrl, useFormatUrl, } from '../link_to'; @@ -114,7 +114,7 @@ export const ExternalLink = React.memo<{ ExternalLink.displayName = 'ExternalLink'; -const IPDetailsLinkComponent: React.FC<{ +const NetworkDetailsLinkComponent: React.FC<{ children?: React.ReactNode; ip: string; flowTarget?: FlowTarget | FlowTargetSourceDest; @@ -125,7 +125,7 @@ const IPDetailsLinkComponent: React.FC<{ (ev) => { ev.preventDefault(); navigateToApp(`${APP_ID}:${SecurityPageName.network}`, { - path: getIPDetailsUrl(encodeURIComponent(encodeIpv6(ip)), flowTarget, search), + path: getNetworkDetailsUrl(encodeURIComponent(encodeIpv6(ip)), flowTarget, search), }); }, [flowTarget, ip, navigateToApp, search] @@ -134,14 +134,14 @@ const IPDetailsLinkComponent: React.FC<{ return ( {children ? children : ip} ); }; -export const IPDetailsLink = React.memo(IPDetailsLinkComponent); +export const NetworkDetailsLink = React.memo(NetworkDetailsLinkComponent); const CaseDetailsLinkComponent: React.FC<{ children?: React.ReactNode; diff --git a/x-pack/plugins/security_solution/public/common/components/links/translations.ts b/x-pack/plugins/security_solution/public/common/components/links/translations.ts index cf7db8bfa816..014acdf3fd55 100644 --- a/x-pack/plugins/security_solution/public/common/components/links/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/links/translations.ts @@ -6,7 +6,7 @@ import { i18n } from '@kbn/i18n'; -export * from '../../../network/components/ip_overview/translations'; +export * from '../../../network/components/details/translations'; export const CASE_DETAILS_LINK_ARIA = (detailName: string) => i18n.translate('xpack.securitySolution.case.caseTable.caseDetailsLinkAria', { diff --git a/x-pack/plugins/security_solution/public/common/components/ml/tables/get_anomalies_network_table_columns.tsx b/x-pack/plugins/security_solution/public/common/components/ml/tables/get_anomalies_network_table_columns.tsx index 52b26a20a8f6..3dd408e5aa82 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml/tables/get_anomalies_network_table_columns.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml/tables/get_anomalies_network_table_columns.tsx @@ -14,7 +14,7 @@ import { Anomaly, AnomaliesByNetwork } from '../types'; import { getRowItemDraggable } from '../../tables/helpers'; import { EntityDraggable } from '../entity_draggable'; import { createCompoundNetworkKey } from './create_compound_key'; -import { IPDetailsLink } from '../../links'; +import { NetworkDetailsLink } from '../../links'; import * as i18n from './translations'; import { getEntries } from '../get_entries'; @@ -46,7 +46,7 @@ export const getAnomaliesNetworkTableColumns = ( rowItem: ip, attrName: anomaliesByNetwork.type, idPrefix: `anomalies-network-table-ip-${createCompoundNetworkKey(anomaliesByNetwork)}`, - render: (item) => , + render: (item) => , }), }, { diff --git a/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.ts b/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.ts index a10e4cf568dd..2964572cb7cf 100644 --- a/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.ts +++ b/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.ts @@ -10,7 +10,7 @@ import { ChromeBreadcrumb } from '../../../../../../../../src/core/public'; import { APP_NAME } from '../../../../../common/constants'; import { StartServices } from '../../../../types'; import { getBreadcrumbs as getHostDetailsBreadcrumbs } from '../../../../hosts/pages/details/utils'; -import { getBreadcrumbs as getIPDetailsBreadcrumbs } from '../../../../network/pages/ip_details'; +import { getBreadcrumbs as getIPDetailsBreadcrumbs } from '../../../../network/pages/details'; import { getBreadcrumbs as getCaseDetailsBreadcrumbs } from '../../../../cases/pages/utils'; import { getBreadcrumbs as getDetectionRulesBreadcrumbs } from '../../../../detections/pages/detection_engine/rules/utils'; import { getBreadcrumbs as getTimelinesBreadcrumbs } from '../../../../timelines/pages'; diff --git a/x-pack/plugins/security_solution/public/common/components/paginated_table/index.tsx b/x-pack/plugins/security_solution/public/common/components/paginated_table/index.tsx index 448fa5844340..f7b69c4fc8ed 100644 --- a/x-pack/plugins/security_solution/public/common/components/paginated_table/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/paginated_table/index.tsx @@ -16,12 +16,12 @@ import { EuiLoadingContent, EuiPagination, EuiPopover, - Direction, } from '@elastic/eui'; import { noop } from 'lodash/fp'; import React, { FC, memo, useState, useEffect, ComponentType } from 'react'; import styled from 'styled-components'; +import { Direction } from '../../../../common/search_strategy'; import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../common/constants'; import { AuthTableColumns } from '../../../hosts/components/authentications_table'; import { HostsTableColumns } from '../../../hosts/components/hosts_table'; @@ -29,11 +29,11 @@ import { NetworkDnsColumns } from '../../../network/components/network_dns_table import { NetworkHttpColumns } from '../../../network/components/network_http_table/columns'; import { NetworkTopNFlowColumns, - NetworkTopNFlowColumnsIpDetails, + NetworkTopNFlowColumnsNetworkDetails, } from '../../../network/components/network_top_n_flow_table/columns'; import { NetworkTopCountriesColumns, - NetworkTopCountriesColumnsIpDetails, + NetworkTopCountriesColumnsNetworkDetails, } from '../../../network/components/network_top_countries_table/columns'; import { TlsColumns } from '../../../network/components/tls_table/columns'; import { UncommonProcessTableColumns } from '../../../hosts/components/uncommon_process_table'; @@ -78,9 +78,9 @@ declare type BasicTableColumns = | NetworkDnsColumns | NetworkHttpColumns | NetworkTopCountriesColumns - | NetworkTopCountriesColumnsIpDetails + | NetworkTopCountriesColumnsNetworkDetails | NetworkTopNFlowColumns - | NetworkTopNFlowColumnsIpDetails + | NetworkTopNFlowColumnsNetworkDetails | TlsColumns | UncommonProcessTableColumns | UsersColumns; diff --git a/x-pack/plugins/security_solution/public/common/lib/connectors/config.ts b/x-pack/plugins/security_solution/public/common/lib/connectors/config.ts index 833f85712b5f..9e6982ea2030 100644 --- a/x-pack/plugins/security_solution/public/common/lib/connectors/config.ts +++ b/x-pack/plugins/security_solution/public/common/lib/connectors/config.ts @@ -4,14 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -// eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ServiceNowConnectorConfiguration } from '../../../../../triggers_actions_ui/public/common'; -import { connector as jiraConnectorConfig } from './jira/config'; +/* eslint-disable @kbn/eslint/no-restricted-paths */ + +import { + ServiceNowConnectorConfiguration, + JiraConnectorConfiguration, +} from '../../../../../triggers_actions_ui/public/common'; import { connector as resilientConnectorConfig } from './resilient/config'; import { ConnectorConfiguration } from './types'; export const connectorsConfiguration: Record = { '.servicenow': ServiceNowConnectorConfiguration as ConnectorConfiguration, - '.jira': jiraConnectorConfig, + '.jira': JiraConnectorConfiguration as ConnectorConfiguration, '.resilient': resilientConnectorConfig, }; diff --git a/x-pack/plugins/security_solution/public/common/lib/connectors/index.ts b/x-pack/plugins/security_solution/public/common/lib/connectors/index.ts index f32e1e0df184..33afa82c84f3 100644 --- a/x-pack/plugins/security_solution/public/common/lib/connectors/index.ts +++ b/x-pack/plugins/security_solution/public/common/lib/connectors/index.ts @@ -4,5 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { getActionType as jiraActionType } from './jira'; export { getActionType as resilientActionType } from './resilient'; diff --git a/x-pack/plugins/security_solution/public/common/lib/connectors/jira/flyout.tsx b/x-pack/plugins/security_solution/public/common/lib/connectors/jira/flyout.tsx deleted file mode 100644 index 0737db3cd08e..000000000000 --- a/x-pack/plugins/security_solution/public/common/lib/connectors/jira/flyout.tsx +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import React from 'react'; -import { - EuiFieldText, - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, - EuiFieldPassword, - EuiSpacer, -} from '@elastic/eui'; - -import * as i18n from './translations'; -import { ConnectorFlyoutFormProps } from '../types'; -import { JiraActionConnector } from './types'; -import { withConnectorFlyout } from '../components/connector_flyout'; - -const JiraConnectorForm: React.FC> = ({ - errors, - action, - onChangeSecret, - onBlurSecret, - onChangeConfig, - onBlurConfig, -}) => { - const { projectKey } = action.config; - const { email, apiToken } = action.secrets; - const isProjectKeyInvalid: boolean = errors.projectKey.length > 0 && projectKey != null; - const isEmailInvalid: boolean = errors.email.length > 0 && email != null; - const isApiTokenInvalid: boolean = errors.apiToken.length > 0 && apiToken != null; - - return ( - <> - - - - onChangeConfig('projectKey', evt.target.value)} - onBlur={() => onBlurConfig('projectKey')} - /> - - - - - - - - onChangeSecret('email', evt.target.value)} - onBlur={() => onBlurSecret('email')} - /> - - - - - - - - onChangeSecret('apiToken', evt.target.value)} - onBlur={() => onBlurSecret('apiToken')} - /> - - - - - ); -}; - -export const JiraConnectorFlyout = withConnectorFlyout({ - ConnectorFormComponent: JiraConnectorForm, - secretKeys: ['email', 'apiToken'], - configKeys: ['projectKey'], - connectorActionTypeId: '.jira', -}); - -// eslint-disable-next-line import/no-default-export -export { JiraConnectorFlyout as default }; diff --git a/x-pack/plugins/security_solution/public/common/lib/connectors/jira/index.tsx b/x-pack/plugins/security_solution/public/common/lib/connectors/jira/index.tsx deleted file mode 100644 index cead392010dc..000000000000 --- a/x-pack/plugins/security_solution/public/common/lib/connectors/jira/index.tsx +++ /dev/null @@ -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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { lazy } from 'react'; -import { - ValidationResult, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../triggers_actions_ui/public/types'; - -import { connector } from './config'; -import { createActionType } from '../utils'; -import logo from './logo.svg'; -import { JiraActionConnector } from './types'; -import * as i18n from './translations'; - -interface Errors { - projectKey: string[]; - email: string[]; - apiToken: string[]; -} - -const validateConnector = (action: JiraActionConnector): ValidationResult => { - const errors: Errors = { - projectKey: [], - email: [], - apiToken: [], - }; - - if (!action.config.projectKey) { - errors.projectKey = [...errors.projectKey, i18n.JIRA_PROJECT_KEY_REQUIRED]; - } - - if (!action.secrets.email) { - errors.email = [...errors.email, i18n.JIRA_EMAIL_REQUIRED]; - } - - if (!action.secrets.apiToken) { - errors.apiToken = [...errors.apiToken, i18n.JIRA_API_TOKEN_REQUIRED]; - } - - return { errors }; -}; - -export const getActionType = createActionType({ - id: connector.id, - iconClass: logo, - selectMessage: i18n.JIRA_DESC, - actionTypeTitle: connector.name, - validateConnector, - actionConnectorFields: lazy(() => import('./flyout')), -}); diff --git a/x-pack/plugins/security_solution/public/common/lib/connectors/jira/translations.ts b/x-pack/plugins/security_solution/public/common/lib/connectors/jira/translations.ts deleted file mode 100644 index d7abf77a58d4..000000000000 --- a/x-pack/plugins/security_solution/public/common/lib/connectors/jira/translations.ts +++ /dev/null @@ -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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { i18n } from '@kbn/i18n'; - -export * from '../translations'; - -export const JIRA_DESC = i18n.translate( - 'xpack.securitySolution.case.connectors.jira.selectMessageText', - { - defaultMessage: 'Push or update Security case data to a new issue in Jira', - } -); - -export const JIRA_TITLE = i18n.translate( - 'xpack.securitySolution.case.connectors.jira.actionTypeTitle', - { - defaultMessage: 'Jira', - } -); - -export const JIRA_PROJECT_KEY_LABEL = i18n.translate( - 'xpack.securitySolution.case.connectors.jira.projectKey', - { - defaultMessage: 'Project key', - } -); - -export const JIRA_PROJECT_KEY_REQUIRED = i18n.translate( - 'xpack.securitySolution.case.connectors.jira.requiredProjectKeyTextField', - { - defaultMessage: 'Project key is required', - } -); - -export const JIRA_EMAIL_LABEL = i18n.translate( - 'xpack.securitySolution.case.connectors.jira.emailTextFieldLabel', - { - defaultMessage: 'Email or Username', - } -); - -export const JIRA_EMAIL_REQUIRED = i18n.translate( - 'xpack.securitySolution.case.connectors.jira.requiredEmailTextField', - { - defaultMessage: 'Email or Username is required', - } -); - -export const JIRA_API_TOKEN_LABEL = i18n.translate( - 'xpack.securitySolution.case.connectors.jira.apiTokenTextFieldLabel', - { - defaultMessage: 'API token or Password', - } -); - -export const JIRA_API_TOKEN_REQUIRED = i18n.translate( - 'xpack.securitySolution.case.connectors.jira.requiredApiTokenTextField', - { - defaultMessage: 'API token or Password is required', - } -); - -export const MAPPING_FIELD_SUMMARY = i18n.translate( - 'xpack.securitySolution.case.configureCases.mappingFieldSummary', - { - defaultMessage: 'Summary', - } -); diff --git a/x-pack/plugins/security_solution/public/common/lib/connectors/jira/types.ts b/x-pack/plugins/security_solution/public/common/lib/connectors/jira/types.ts deleted file mode 100644 index fafb4a0d41fb..000000000000 --- a/x-pack/plugins/security_solution/public/common/lib/connectors/jira/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -/* eslint-disable no-restricted-imports */ -/* eslint-disable @kbn/eslint/no-restricted-paths */ - -import { - JiraPublicConfigurationType, - JiraSecretConfigurationType, -} from '../../../../../../actions/server/builtin_action_types/jira/types'; - -export { JiraFieldsType } from '../../../../../../case/common/api/connectors'; - -export * from '../types'; - -export interface JiraActionConnector { - config: JiraPublicConfigurationType; - secrets: JiraSecretConfigurationType; -} diff --git a/x-pack/plugins/security_solution/public/common/mock/global_state.ts b/x-pack/plugins/security_solution/public/common/mock/global_state.ts index 2849e8ffabd3..a74c9a6d2009 100644 --- a/x-pack/plugins/security_solution/public/common/mock/global_state.ts +++ b/x-pack/plugins/security_solution/public/common/mock/global_state.ts @@ -11,9 +11,9 @@ import { HostsFields, NetworkDnsFields, NetworkTopTablesFields, - TlsFields, - UsersFields, -} from '../../graphql/types'; + NetworkTlsFields, + NetworkUsersFields, +} from '../../../common/search_strategy'; import { State } from '../store'; import { defaultHeaders } from './header'; @@ -100,7 +100,7 @@ export const mockGlobalState: State = { [networkModel.NetworkTableType.tls]: { activePage: 0, limit: 10, - sort: { field: TlsFields._id, direction: Direction.desc }, + sort: { field: NetworkTlsFields._id, direction: Direction.desc }, }, [networkModel.NetworkTableType.http]: { activePage: 0, @@ -116,37 +116,37 @@ export const mockGlobalState: State = { details: { flowTarget: FlowTarget.source, queries: { - [networkModel.IpDetailsTableType.topCountriesDestination]: { + [networkModel.NetworkDetailsTableType.topCountriesDestination]: { activePage: 0, limit: 10, sort: { field: NetworkTopTablesFields.bytes_out, direction: Direction.desc }, }, - [networkModel.IpDetailsTableType.topCountriesSource]: { + [networkModel.NetworkDetailsTableType.topCountriesSource]: { activePage: 0, limit: 10, sort: { field: NetworkTopTablesFields.bytes_out, direction: Direction.desc }, }, - [networkModel.IpDetailsTableType.topNFlowSource]: { + [networkModel.NetworkDetailsTableType.topNFlowSource]: { activePage: 0, limit: 10, sort: { field: NetworkTopTablesFields.bytes_out, direction: Direction.desc }, }, - [networkModel.IpDetailsTableType.topNFlowDestination]: { + [networkModel.NetworkDetailsTableType.topNFlowDestination]: { activePage: 0, limit: 10, sort: { field: NetworkTopTablesFields.bytes_out, direction: Direction.desc }, }, - [networkModel.IpDetailsTableType.tls]: { + [networkModel.NetworkDetailsTableType.tls]: { activePage: 0, limit: 10, - sort: { field: TlsFields._id, direction: Direction.desc }, + sort: { field: NetworkTlsFields._id, direction: Direction.desc }, }, - [networkModel.IpDetailsTableType.users]: { + [networkModel.NetworkDetailsTableType.users]: { activePage: 0, limit: 10, - sort: { field: UsersFields.name, direction: Direction.asc }, + sort: { field: NetworkUsersFields.name, direction: Direction.asc }, }, - [networkModel.IpDetailsTableType.http]: { + [networkModel.NetworkDetailsTableType.http]: { activePage: 0, limit: 10, sort: { direction: Direction.desc }, diff --git a/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx b/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx index c7810af13eb7..5a4eaad72ac3 100644 --- a/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/test_providers.tsx @@ -95,6 +95,7 @@ export const useFormFieldMock = (options?: Partial): FieldHook => { clearErrors: jest.fn(), validate: jest.fn(), reset: jest.fn(), + __isIncludedInOutput: true, __serializeValue: jest.fn(), ...options, }; diff --git a/x-pack/plugins/security_solution/public/common/store/actions.ts b/x-pack/plugins/security_solution/public/common/store/actions.ts index cd8836e38bfe..6b446ab6692d 100644 --- a/x-pack/plugins/security_solution/public/common/store/actions.ts +++ b/x-pack/plugins/security_solution/public/common/store/actions.ts @@ -7,10 +7,16 @@ import { EndpointAction } from '../../management/pages/endpoint_hosts/store/action'; import { PolicyListAction } from '../../management/pages/policy/store/policy_list'; import { PolicyDetailsAction } from '../../management/pages/policy/store/policy_details'; +import { TrustedAppsPageAction } from '../../management/pages/trusted_apps/store/action'; export { appActions } from './app'; export { dragAndDropActions } from './drag_and_drop'; export { inputsActions } from './inputs'; import { RoutingAction } from './routing'; -export type AppAction = EndpointAction | RoutingAction | PolicyListAction | PolicyDetailsAction; +export type AppAction = + | EndpointAction + | RoutingAction + | PolicyListAction + | PolicyDetailsAction + | TrustedAppsPageAction; diff --git a/x-pack/plugins/security_solution/public/common/store/routing/action.ts b/x-pack/plugins/security_solution/public/common/store/routing/action.ts index ae5e4eb32d47..d0cc38970ca2 100644 --- a/x-pack/plugins/security_solution/public/common/store/routing/action.ts +++ b/x-pack/plugins/security_solution/public/common/store/routing/action.ts @@ -6,7 +6,7 @@ import { AppLocation, Immutable } from '../../../../common/endpoint/types'; -interface UserChangedUrl { +export interface UserChangedUrl { readonly type: 'userChangedUrl'; readonly payload: Immutable; } diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/all_rules_tables/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/all_rules_tables/index.tsx index 8fd3f648bc81..bfb23ff6af6a 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/all_rules_tables/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/all_rules_tables/index.tsx @@ -20,7 +20,7 @@ import { RulesColumns, RuleStatusRowItemType, } from '../../../pages/detection_engine/rules/all/columns'; -import { Rule, Rules } from '../../../containers/detection_engine/rules/types'; +import { Rule, Rules, RulesSortingFields } from '../../../containers/detection_engine/rules/types'; import { AllRulesTabs } from '../../../pages/detection_engine/rules/all'; // EuiBasicTable give me a hardtime with adding the ref attributes so I went the easy way @@ -30,7 +30,7 @@ const MyEuiBasicTable = styled(EuiBasicTable as any)`` as any; export interface SortingType { sort: { - field: 'enabled'; + field: RulesSortingFields; direction: Direction; }; } @@ -48,12 +48,7 @@ interface AllRulesTablesProps { rules: Rules; rulesColumns: RulesColumns[]; rulesStatuses: RuleStatusRowItemType[]; - sorting: { - sort: { - field: 'enabled'; - direction: Direction; - }; - }; + sorting: SortingType; tableOnChangeCallback: ({ page, sort }: EuiBasicTableOnChange) => void; tableRef?: React.MutableRefObject; selectedTab: AllRulesTabs; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/__snapshots__/index.test.tsx.snap index 1ed55774f935..4d21a983c970 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/__snapshots__/index.test.tsx.snap @@ -40,7 +40,7 @@ exports[`RuleActionsOverflow snapshots renders correctly against snapshot 1`] = icon="copy" onClick={[Function]} > - Duplicate rule… + Duplicate rule , - Delete rule… + Delete rule , ] } diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts index cd1ded544cfe..2a15cf7b95ce 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.test.ts @@ -202,7 +202,7 @@ describe('Detections Rules API', () => { expect(fetchMock).toHaveBeenCalledWith('/api/detection_engine/rules/_find', { method: 'GET', query: { - filter: 'alert.attributes.tags: "hello" AND alert.attributes.tags: "world"', + filter: 'alert.attributes.tags: "hello" OR alert.attributes.tags: "world"', page: 1, per_page: 20, sort_field: 'enabled', @@ -297,7 +297,7 @@ describe('Detections Rules API', () => { method: 'GET', query: { filter: - 'alert.attributes.name: ruleName AND alert.attributes.tags: "__internal_immutable:false" AND alert.attributes.tags: "__internal_immutable:true" AND alert.attributes.tags: "hello" AND alert.attributes.tags: "world"', + 'alert.attributes.name: ruleName AND alert.attributes.tags: "__internal_immutable:false" AND alert.attributes.tags: "__internal_immutable:true" AND (alert.attributes.tags: "hello" OR alert.attributes.tags: "world")', page: 1, per_page: 20, sort_field: 'enabled', diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts index e254516d1107..b66154fbb57d 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts @@ -107,7 +107,7 @@ export const fetchRules = async ({ }, signal, }: FetchRulesProps): Promise => { - const filters = [ + const filtersWithoutTags = [ ...(filterOptions.filter.length ? [`alert.attributes.name: ${filterOptions.filter}`] : []), ...(filterOptions.showCustomRules ? [`alert.attributes.tags: "__internal_immutable:false"`] @@ -115,15 +115,27 @@ export const fetchRules = async ({ ...(filterOptions.showElasticRules ? [`alert.attributes.tags: "__internal_immutable:true"`] : []), + ].join(' AND '); + + const tags = [ ...(filterOptions.tags?.map((t) => `alert.attributes.tags: "${t.replace(/"/g, '\\"')}"`) ?? []), - ]; + ].join(' OR '); + + const filterString = + filtersWithoutTags !== '' && tags !== '' + ? `${filtersWithoutTags} AND (${tags})` + : filtersWithoutTags + tags; + + const getFieldNameForSortField = (field: string) => { + return field === 'name' ? `${field}.keyword` : field; + }; const query = { page: pagination.page, per_page: pagination.perPage, - sort_field: filterOptions.sortField, + sort_field: getFieldNameForSortField(filterOptions.sortField), sort_order: filterOptions.sortOrder, - ...(filters.length ? { filter: filters.join(' AND ') } : {}), + ...(filterString !== '' ? { filter: filterString } : {}), }; return KibanaServices.get().http.fetch( diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts index e94e57ad82bc..49579e893029 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts @@ -149,9 +149,10 @@ export interface FetchRulesProps { signal: AbortSignal; } +export type RulesSortingFields = 'enabled' | 'updated_at' | 'name' | 'created_at'; export interface FilterOptions { filter: string; - sortField: string; + sortField: RulesSortingFields; sortOrder: SortOrder; showCustomRules?: boolean; showElasticRules?: boolean; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx index ea36a0cb0b48..866d3e896a71 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx @@ -99,7 +99,6 @@ interface GetColumns { reFetchRules: (refreshPrePackagedRule?: boolean) => void; } -// Michael: Are we able to do custom, in-table-header filters, as shown in my wireframes? export const getColumns = ({ dispatch, dispatchToaster, @@ -127,7 +126,8 @@ export const getColumns = ({ ), truncateText: true, - width: '24%', + width: '20%', + sortable: true, }, { field: 'risk_score', @@ -138,14 +138,14 @@ export const getColumns = ({ ), truncateText: true, - width: '14%', + width: '10%', }, { field: 'severity', name: i18n.COLUMN_SEVERITY, render: (value: Rule['severity']) => , truncateText: true, - width: '16%', + width: '12%', }, { field: 'status_date', @@ -160,7 +160,7 @@ export const getColumns = ({ ); }, truncateText: true, - width: '20%', + width: '14%', }, { field: 'status', @@ -174,9 +174,40 @@ export const getColumns = ({ ); }, - width: '16%', + width: '12%', truncateText: true, }, + { + field: 'updated_at', + name: i18n.COLUMN_LAST_UPDATE, + render: (value: Rule['updated_at']) => { + return value == null ? ( + getEmptyTagValue() + ) : ( + + + + ); + }, + sortable: true, + truncateText: true, + width: '14%', + }, + { + field: 'version', + name: i18n.COLUMN_VERSION, + render: (value: Rule['version']) => { + return value == null ? ( + getEmptyTagValue() + ) : ( + + {value} + + ); + }, + truncateText: true, + width: '10%', + }, { field: 'tags', name: i18n.COLUMN_TAGS, @@ -190,7 +221,7 @@ export const getColumns = ({ ), truncateText: true, - width: '20%', + width: '14%', }, { align: 'center', diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx index 110691328b13..306adbd63ee7 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx @@ -24,6 +24,7 @@ import { Rule, PaginationOptions, exportRules, + RulesSortingFields, } from '../../../../containers/detection_engine/rules'; import { HeaderSection } from '../../../../../common/components/header_section'; import { @@ -53,12 +54,12 @@ import { hasMlLicense } from '../../../../../../common/machine_learning/has_ml_l import { SecurityPageName } from '../../../../../app/types'; import { useFormatUrl } from '../../../../../common/components/link_to'; -const SORT_FIELD = 'enabled'; +const INITIAL_SORT_FIELD = 'enabled'; const initialState: State = { exportRuleIds: [], filterOptions: { filter: '', - sortField: SORT_FIELD, + sortField: INITIAL_SORT_FIELD, sortOrder: 'desc', }, loadingRuleIds: [], @@ -164,8 +165,13 @@ export const AllRules = React.memo( }); const sorting = useMemo( - (): SortingType => ({ sort: { field: 'enabled', direction: filterOptions.sortOrder } }), - [filterOptions.sortOrder] + (): SortingType => ({ + sort: { + field: filterOptions.sortField, + direction: filterOptions.sortOrder, + }, + }), + [filterOptions] ); const prePackagedRuleStatus = getPrePackagedRuleStatus( @@ -215,7 +221,7 @@ export const AllRules = React.memo( dispatch({ type: 'updateFilterOptions', filterOptions: { - sortField: SORT_FIELD, // Only enabled is supported for sorting currently + sortField: (sort?.field as RulesSortingFields) ?? INITIAL_SORT_FIELD, // Narrowing EuiBasicTable sorting types sortOrder: sort?.direction ?? 'desc', }, pagination: { page: page.index + 1, perPage: page.size }, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx index 49fe3438664c..4fe0bc8f835d 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx @@ -4,7 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Dispatch, SetStateAction, useState } from 'react'; +import React, { + ChangeEvent, + Dispatch, + SetStateAction, + useCallback, + useEffect, + useMemo, + useState, +} from 'react'; import { EuiFilterButton, EuiFilterSelectItem, @@ -13,6 +21,8 @@ import { EuiPanel, EuiPopover, EuiText, + EuiFieldSearch, + EuiPopoverTitle, } from '@elastic/eui'; import styled from 'styled-components'; import * as i18n from '../../translations'; @@ -37,12 +47,39 @@ const ScrollableDiv = styled.div` * @param tags to display for filtering * @param onSelectedTagsChanged change listener to be notified when tag selection changes */ -export const TagsFilterPopoverComponent = ({ +const TagsFilterPopoverComponent = ({ tags, selectedTags, onSelectedTagsChanged, }: TagsFilterPopoverProps) => { + const sortedTags = useMemo(() => { + return tags.sort((a: string, b: string) => a.toLowerCase().localeCompare(b.toLowerCase())); // Case insensitive + }, [tags]); const [isTagPopoverOpen, setIsTagPopoverOpen] = useState(false); + const [searchInput, setSearchInput] = useState(''); + const [filterTags, setFilterTags] = useState(sortedTags); + + const tagsComponent = useMemo(() => { + return filterTags.map((tag, index) => ( + toggleSelectedGroup(tag, selectedTags, onSelectedTagsChanged)} + > + {`${tag}`} + + )); + }, [onSelectedTagsChanged, selectedTags, filterTags]); + + const onSearchInputChange = useCallback((event: ChangeEvent) => { + setSearchInput(event.target.value); + }, []); + + useEffect(() => { + setFilterTags( + sortedTags.filter((tag) => tag.toLowerCase().includes(searchInput.toLowerCase())) + ); + }, [sortedTags, searchInput]); return ( - - {tags.map((tag, index) => ( - toggleSelectedGroup(tag, selectedTags, onSelectedTagsChanged)} - > - {`${tag}`} - - ))} - - {tags.length === 0 && ( + + + + {tagsComponent} + {filterTags.length === 0 && ( diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts index b20c8de8ed58..09503fcf1ef0 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts @@ -16,7 +16,7 @@ export const BACK_TO_DETECTIONS = i18n.translate( export const IMPORT_RULE = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.importRuleTitle', { - defaultMessage: 'Import rule…', + defaultMessage: 'Import rule', } ); @@ -100,7 +100,7 @@ export const BATCH_ACTION_ACTIVATE_SELECTED_ERROR = (totalRules: number) => 'xpack.securitySolution.detectionEngine.rules.allRules.batchActions.activateSelectedErrorTitle', { values: { totalRules }, - defaultMessage: 'Error activating {totalRules, plural, =1 {rule} other {rules}}…', + defaultMessage: 'Error activating {totalRules, plural, =1 {rule} other {rules}}', } ); @@ -116,7 +116,7 @@ export const BATCH_ACTION_DEACTIVATE_SELECTED_ERROR = (totalRules: number) => 'xpack.securitySolution.detectionEngine.rules.allRules.batchActions.deactivateSelectedErrorTitle', { values: { totalRules }, - defaultMessage: 'Error deactivating {totalRules, plural, =1 {rule} other {rules}}…', + defaultMessage: 'Error deactivating {totalRules, plural, =1 {rule} other {rules}}', } ); @@ -130,14 +130,14 @@ export const BATCH_ACTION_EXPORT_SELECTED = i18n.translate( export const BATCH_ACTION_DUPLICATE_SELECTED = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.batchActions.duplicateSelectedTitle', { - defaultMessage: 'Duplicate selected…', + defaultMessage: 'Duplicate selected', } ); export const BATCH_ACTION_DELETE_SELECTED = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.batchActions.deleteSelectedTitle', { - defaultMessage: 'Delete selected…', + defaultMessage: 'Delete selected', } ); @@ -153,7 +153,7 @@ export const BATCH_ACTION_DELETE_SELECTED_ERROR = (totalRules: number) => 'xpack.securitySolution.detectionEngine.rules.allRules.batchActions.deleteSelectedErrorTitle', { values: { totalRules }, - defaultMessage: 'Error deleting {totalRules, plural, =1 {rule} other {rules}}…', + defaultMessage: 'Error deleting {totalRules, plural, =1 {rule} other {rules}}', } ); @@ -224,7 +224,7 @@ export const DUPLICATE = i18n.translate( export const DUPLICATE_RULE = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.actions.duplicateRuleDescription', { - defaultMessage: 'Duplicate rule…', + defaultMessage: 'Duplicate rule', } ); @@ -241,7 +241,7 @@ export const SUCCESSFULLY_DUPLICATED_RULES = (totalRules: number) => export const DUPLICATE_RULE_ERROR = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.actions.duplicateRuleErrorDescription', { - defaultMessage: 'Error duplicating rule…', + defaultMessage: 'Error duplicating rule', } ); @@ -255,7 +255,7 @@ export const EXPORT_RULE = i18n.translate( export const DELETE_RULE = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.actions.deleteeRuleDescription', { - defaultMessage: 'Delete rule…', + defaultMessage: 'Delete rule', } ); @@ -287,6 +287,13 @@ export const COLUMN_LAST_COMPLETE_RUN = i18n.translate( } ); +export const COLUMN_LAST_UPDATE = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.columns.lastUpdateTitle', + { + defaultMessage: 'Last updated', + } +); + export const COLUMN_LAST_RESPONSE = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.columns.lastResponseTitle', { @@ -294,6 +301,13 @@ export const COLUMN_LAST_RESPONSE = i18n.translate( } ); +export const COLUMN_VERSION = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.columns.versionTitle', + { + defaultMessage: 'Version', + } +); + export const COLUMN_TAGS = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.columns.tagsTitle', { diff --git a/x-pack/plugins/security_solution/public/helpers.test.ts b/x-pack/plugins/security_solution/public/helpers.test.ts new file mode 100644 index 000000000000..9244452a23e6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/helpers.test.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { parseRoute } from './helpers'; + +describe('public helpers parseRoute', () => { + it('should properly parse hash route', () => { + const hashSearch = + '?timerange=(global:(linkTo:!(timeline),timerange:(from:%272020-09-06T11:43:55.814Z%27,fromStr:now-24h,kind:relative,to:%272020-09-07T11:43:55.814Z%27,toStr:now)),timeline:(linkTo:!(global),timerange:(from:%272020-09-06T11:43:55.814Z%27,fromStr:now-24h,kind:relative,to:%272020-09-07T11:43:55.814Z%27,toStr:now)))'; + const hashLocation = { + hash: `#/detections/rules/id/78acc090-bbaa-4a86-916b-ea44784324ae/edit${hashSearch}`, + pathname: '/app/siem', + search: '', + }; + + expect(parseRoute(hashLocation)).toEqual({ + pageName: 'detections', + path: `/rules/id/78acc090-bbaa-4a86-916b-ea44784324ae/edit${hashSearch}`, + search: hashSearch, + }); + }); + + it('should properly parse non-hash route', () => { + const nonHashLocation = { + hash: '', + pathname: '/app/security/detections/rules/id/78acc090-bbaa-4a86-916b-ea44784324ae/edit', + search: + '?timerange=(global:(linkTo:!(timeline),timerange:(from:%272020-09-06T11:43:55.814Z%27,fromStr:now-24h,kind:relative,to:%272020-09-07T11:43:55.814Z%27,toStr:now)),timeline:(linkTo:!(global),timerange:(from:%272020-09-06T11:43:55.814Z%27,fromStr:now-24h,kind:relative,to:%272020-09-07T11:43:55.814Z%27,toStr:now)))', + }; + + expect(parseRoute(nonHashLocation)).toEqual({ + pageName: 'detections', + path: `/rules/id/78acc090-bbaa-4a86-916b-ea44784324ae/edit${nonHashLocation.search}`, + search: nonHashLocation.search, + }); + }); + + it('should properly parse non-hash subplugin route', () => { + const nonHashLocation = { + hash: '', + pathname: '/app/security/detections', + search: + '?timerange=(global:(linkTo:!(timeline),timerange:(from:%272020-09-06T11:43:55.814Z%27,fromStr:now-24h,kind:relative,to:%272020-09-07T11:43:55.814Z%27,toStr:now)),timeline:(linkTo:!(global),timerange:(from:%272020-09-06T11:43:55.814Z%27,fromStr:now-24h,kind:relative,to:%272020-09-07T11:43:55.814Z%27,toStr:now)))', + }; + + expect(parseRoute(nonHashLocation)).toEqual({ + pageName: 'detections', + path: `${nonHashLocation.search}`, + search: nonHashLocation.search, + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/helpers.ts b/x-pack/plugins/security_solution/public/helpers.ts index 63c3f3ea81d9..92f3d2390755 100644 --- a/x-pack/plugins/security_solution/public/helpers.ts +++ b/x-pack/plugins/security_solution/public/helpers.ts @@ -4,6 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ +import { isEmpty } from 'lodash/fp'; + import { CoreStart } from '../../../../src/core/public'; import { APP_ID } from '../common/constants'; import { @@ -13,13 +15,37 @@ import { import { SecurityPageName } from './app/types'; import { InspectResponse } from './types'; +export const parseRoute = (location: Pick) => { + if (!isEmpty(location.hash)) { + const hashPath = location.hash.split('?'); + const search = hashPath.length >= 1 ? `?${hashPath[1]}` : ''; + const pageRoute = hashPath.length > 0 ? hashPath[0].split('/') : []; + const pageName = pageRoute.length >= 1 ? pageRoute[1] : ''; + const path = `/${pageRoute.slice(2).join('/') ?? ''}${search}`; + + return { + pageName, + path, + search, + }; + } + + const search = location.search; + const pageRoute = location.pathname.split('/'); + const pageName = pageRoute[3]; + const subpluginPath = pageRoute.length > 4 ? `/${pageRoute.slice(4).join('/')}` : ''; + const path = `${subpluginPath}${search}`; + + return { + pageName, + path, + search, + }; +}; + export const manageOldSiemRoutes = async (coreStart: CoreStart) => { const { application } = coreStart; - const hashPath = window.location.hash.split('?'); - const search = hashPath.length >= 1 ? hashPath[1] : ''; - const pageRoute = hashPath.length > 0 ? hashPath[0].split('/') : []; - const pageName = pageRoute.length >= 1 ? pageRoute[1] : ''; - const path = `/${pageRoute.slice(2).join('/') ?? ''}?${search}`; + const { pageName, path, search } = parseRoute(window.location); switch (pageName) { case SecurityPageName.overview: @@ -73,7 +99,7 @@ export const manageOldSiemRoutes = async (coreStart: CoreStart) => { default: application.navigateToApp(`${APP_ID}:${SecurityPageName.overview}`, { replace: true, - path: `?${search}`, + path: `${search}`, }); break; } diff --git a/x-pack/plugins/security_solution/public/hosts/components/authentications_table/index.tsx b/x-pack/plugins/security_solution/public/hosts/components/authentications_table/index.tsx index 8e2b47769adf..3d291d9bf7b2 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/authentications_table/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/authentications_table/index.tsx @@ -20,7 +20,7 @@ import { import { escapeDataProviderId } from '../../../common/components/drag_and_drop/helpers'; import { getEmptyTagValue } from '../../../common/components/empty_value'; import { FormattedRelativePreferenceDate } from '../../../common/components/formatted_date'; -import { HostDetailsLink, IPDetailsLink } from '../../../common/components/links'; +import { HostDetailsLink, NetworkDetailsLink } from '../../../common/components/links'; import { Columns, ItemsPerRow, PaginatedTable } from '../../../common/components/paginated_table'; import { IS_OPERATOR } from '../../../timelines/components/timeline/data_providers/data_provider'; import { Provider } from '../../../timelines/components/timeline/data_providers/provider'; @@ -264,7 +264,7 @@ const getAuthenticationColumns = (): AuthTableColumns => [ : null, attrName: 'source.ip', idPrefix: `authentications-table-${node._id}-lastSuccessSource`, - render: (item) => , + render: (item) => , }), }, { @@ -309,7 +309,7 @@ const getAuthenticationColumns = (): AuthTableColumns => [ : null, attrName: 'source.ip', idPrefix: `authentications-table-${node._id}-lastFailureSource`, - render: (item) => , + render: (item) => , }), }, { diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx index 49b63a5f76a1..d8cd59f119d5 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx @@ -9,6 +9,7 @@ import { noop } from 'lodash/fp'; import React, { useEffect, useCallback, useMemo } from 'react'; import { connect, ConnectedProps } from 'react-redux'; +import { HostItem } from '../../../../common/search_strategy'; import { SecurityPageName } from '../../../app/types'; import { UpdateDateRange } from '../../../common/components/charts/common'; import { FiltersGlobal } from '../../../common/components/filters_global'; @@ -137,7 +138,7 @@ const HostDetailsComponent = React.memo( inspect={inspect} refetch={refetch} setQuery={setQuery} - data={hostOverview} + data={hostOverview as HostItem} anomaliesData={anomaliesData} isLoadingAnomaliesData={isLoadingAnomaliesData} loading={loading} diff --git a/x-pack/plugins/security_solution/public/management/common/constants.ts b/x-pack/plugins/security_solution/public/management/common/constants.ts index 06f0f09bcf54..cd4ce743bb70 100644 --- a/x-pack/plugins/security_solution/public/management/common/constants.ts +++ b/x-pack/plugins/security_solution/public/management/common/constants.ts @@ -24,6 +24,12 @@ export const MANAGEMENT_STORE_POLICY_LIST_NAMESPACE = 'policyList'; export const MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE = 'policyDetails'; /** Namespace within the Management state where endpoint-host state is maintained */ export const MANAGEMENT_STORE_ENDPOINTS_NAMESPACE = 'endpoints'; +/** Namespace within the Management state where trusted apps page state is maintained */ +export const MANAGEMENT_STORE_TRUSTED_APPS_NAMESPACE = 'trustedApps'; + +export const MANAGEMENT_PAGE_SIZE_OPTIONS: readonly number[] = [10, 20, 50]; +export const MANAGEMENT_DEFAULT_PAGE = 0; +export const MANAGEMENT_DEFAULT_PAGE_SIZE = 10; // --[ DEFAULTS ]--------------------------------------------------------------------------- /** The default polling interval to start all polling pages */ diff --git a/x-pack/plugins/security_solution/public/management/common/routing.test.ts b/x-pack/plugins/security_solution/public/management/common/routing.test.ts new file mode 100644 index 000000000000..7a36654dcffc --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/common/routing.test.ts @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { extractListPaginationParams, getTrustedAppsListPath } from './routing'; +import { MANAGEMENT_DEFAULT_PAGE, MANAGEMENT_DEFAULT_PAGE_SIZE } from './constants'; + +describe('routing', () => { + describe('extractListPaginationParams()', () => { + it('extracts default page index when not provided', () => { + expect(extractListPaginationParams({}).page_index).toBe(MANAGEMENT_DEFAULT_PAGE); + }); + + it('extracts default page index when too small value provided', () => { + expect(extractListPaginationParams({ page_index: '-1' }).page_index).toBe( + MANAGEMENT_DEFAULT_PAGE + ); + }); + + it('extracts default page index when not a number provided', () => { + expect(extractListPaginationParams({ page_index: 'a' }).page_index).toBe( + MANAGEMENT_DEFAULT_PAGE + ); + }); + + it('extracts only last page index when multiple values provided', () => { + expect(extractListPaginationParams({ page_index: ['1', '2'] }).page_index).toBe(2); + }); + + it('extracts proper page index when single valid value provided', () => { + expect(extractListPaginationParams({ page_index: '2' }).page_index).toBe(2); + }); + + it('extracts default page size when not provided', () => { + expect(extractListPaginationParams({}).page_size).toBe(MANAGEMENT_DEFAULT_PAGE_SIZE); + }); + + it('extracts default page size when invalid option provided', () => { + expect(extractListPaginationParams({ page_size: '25' }).page_size).toBe( + MANAGEMENT_DEFAULT_PAGE_SIZE + ); + }); + + it('extracts default page size when not a number provided', () => { + expect(extractListPaginationParams({ page_size: 'a' }).page_size).toBe( + MANAGEMENT_DEFAULT_PAGE_SIZE + ); + }); + + it('extracts only last page size when multiple values provided', () => { + expect(extractListPaginationParams({ page_size: ['10', '20'] }).page_size).toBe(20); + }); + + it('extracts proper page size when single valid value provided', () => { + expect(extractListPaginationParams({ page_size: '20' }).page_size).toBe(20); + }); + }); + + describe('getTrustedAppsListPath()', () => { + it('builds proper path when no parameters provided', () => { + expect(getTrustedAppsListPath()).toEqual('/trusted_apps'); + }); + + it('builds proper path when empty parameters provided', () => { + expect(getTrustedAppsListPath({})).toEqual('/trusted_apps'); + }); + + it('builds proper path when no page index provided', () => { + expect(getTrustedAppsListPath({ page_size: 20 })).toEqual('/trusted_apps?page_size=20'); + }); + + it('builds proper path when no page size provided', () => { + expect(getTrustedAppsListPath({ page_index: 2 })).toEqual('/trusted_apps?page_index=2'); + }); + + it('builds proper path when both page index and size provided', () => { + expect(getTrustedAppsListPath({ page_index: 2, page_size: 20 })).toEqual( + '/trusted_apps?page_index=2&page_size=20' + ); + }); + + it('builds proper path when page index is equal to default', () => { + const path = getTrustedAppsListPath({ + page_index: MANAGEMENT_DEFAULT_PAGE, + page_size: 20, + }); + + expect(path).toEqual('/trusted_apps?page_size=20'); + }); + + it('builds proper path when page size is equal to default', () => { + const path = getTrustedAppsListPath({ + page_index: 2, + page_size: MANAGEMENT_DEFAULT_PAGE_SIZE, + }); + + expect(path).toEqual('/trusted_apps?page_index=2'); + }); + + it('builds proper path when both page index and size are equal to default', () => { + const path = getTrustedAppsListPath({ + page_index: MANAGEMENT_DEFAULT_PAGE, + page_size: MANAGEMENT_DEFAULT_PAGE_SIZE, + }); + + expect(path).toEqual('/trusted_apps'); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/common/routing.ts b/x-pack/plugins/security_solution/public/management/common/routing.ts index c5ced6f3bcf5..62f360df9019 100644 --- a/x-pack/plugins/security_solution/public/management/common/routing.ts +++ b/x-pack/plugins/security_solution/public/management/common/routing.ts @@ -10,6 +10,9 @@ import { generatePath } from 'react-router-dom'; import querystring from 'querystring'; import { + MANAGEMENT_DEFAULT_PAGE, + MANAGEMENT_DEFAULT_PAGE_SIZE, + MANAGEMENT_PAGE_SIZE_OPTIONS, MANAGEMENT_ROUTING_ENDPOINTS_PATH, MANAGEMENT_ROUTING_POLICIES_PATH, MANAGEMENT_ROUTING_POLICY_DETAILS_PATH, @@ -86,8 +89,61 @@ export const getPolicyDetailPath = (policyId: string, search?: string) => { })}${appendSearch(search)}`; }; -export const getTrustedAppsListPath = (search?: string) => { - return `${generatePath(MANAGEMENT_ROUTING_TRUSTED_APPS_PATH, { +interface ListPaginationParams { + page_index: number; + page_size: number; +} + +const isDefaultOrMissing = (value: number | undefined, defaultValue: number) => { + return value === undefined || value === defaultValue; +}; + +const normalizeListPaginationParams = ( + params?: Partial +): Partial => { + if (params) { + return { + ...(!isDefaultOrMissing(params.page_index, MANAGEMENT_DEFAULT_PAGE) + ? { page_index: params.page_index } + : {}), + ...(!isDefaultOrMissing(params.page_size, MANAGEMENT_DEFAULT_PAGE_SIZE) + ? { page_size: params.page_size } + : {}), + }; + } else { + return {}; + } +}; + +const extractFirstParamValue = (query: querystring.ParsedUrlQuery, key: string): string => { + const value = query[key]; + + return Array.isArray(value) ? value[value.length - 1] : value; +}; + +const extractPageIndex = (query: querystring.ParsedUrlQuery): number => { + const pageIndex = Number(extractFirstParamValue(query, 'page_index')); + + return !Number.isFinite(pageIndex) || pageIndex < 0 ? MANAGEMENT_DEFAULT_PAGE : pageIndex; +}; + +const extractPageSize = (query: querystring.ParsedUrlQuery): number => { + const pageSize = Number(extractFirstParamValue(query, 'page_size')); + + return MANAGEMENT_PAGE_SIZE_OPTIONS.includes(pageSize) ? pageSize : MANAGEMENT_DEFAULT_PAGE_SIZE; +}; + +export const extractListPaginationParams = ( + query: querystring.ParsedUrlQuery +): ListPaginationParams => ({ + page_index: extractPageIndex(query), + page_size: extractPageSize(query), +}); + +export const getTrustedAppsListPath = (params?: Partial): string => { + const path = generatePath(MANAGEMENT_ROUTING_TRUSTED_APPS_PATH, { tabName: AdministrationSubTab.trustedApps, - })}${appendSearch(search)}`; + }); + + return `${path}${appendSearch(querystring.stringify(normalizeListPaginationParams(params)))}`; }; diff --git a/x-pack/plugins/security_solution/public/management/index.ts b/x-pack/plugins/security_solution/public/management/index.ts index 902ed085bd36..4bd9ac495ada 100644 --- a/x-pack/plugins/security_solution/public/management/index.ts +++ b/x-pack/plugins/security_solution/public/management/index.ts @@ -47,9 +47,7 @@ export class Management { * Cast the ImmutableReducer to a regular reducer for compatibility with * the subplugin architecture (which expects plain redux reducers.) */ - reducer: { - management: managementReducer, - } as ManagementPluginReducer, + reducer: { management: managementReducer } as ManagementPluginReducer, middleware: managementMiddlewareFactory(core, plugins), }, }; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/models/index_pattern.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/models/index_pattern.ts new file mode 100644 index 000000000000..064a591d0f3f --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/models/index_pattern.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { all } from 'deepmerge'; +import { IIndexPattern } from '../../../../../../../../src/plugins/data/common'; +import { Immutable } from '../../../../../common/endpoint/types'; + +export function clone(value: IIndexPattern | Immutable): IIndexPattern { + return all([value]) as IIndexPattern; +} diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts index 5f36af2a2d8e..84d09adfc295 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts @@ -13,6 +13,7 @@ import { ServerApiError } from '../../../../common/types'; import { GetPolicyListResponse } from '../../policy/types'; import { GetPackagesResponse } from '../../../../../../ingest_manager/common'; import { EndpointState } from '../types'; +import { IIndexPattern } from '../../../../../../../../src/plugins/data/public'; interface ServerReturnedEndpointList { type: 'serverReturnedEndpointList'; @@ -86,6 +87,15 @@ interface ServerReturnedEndpointExistValue { payload: boolean; } +interface ServerReturnedMetadataPatterns { + type: 'serverReturnedMetadataPatterns'; + payload: IIndexPattern[]; +} + +interface ServerFailedToReturnMetadataPatterns { + type: 'serverFailedToReturnMetadataPatterns'; + payload: ServerApiError; +} interface UserUpdatedEndpointListRefreshOptions { type: 'userUpdatedEndpointListRefreshOptions'; payload: { @@ -112,6 +122,8 @@ export type EndpointAction = | ServerReturnedEndpointExistValue | ServerCancelledPolicyItemsLoading | ServerReturnedEndpointPackageInfo + | ServerReturnedMetadataPatterns + | ServerFailedToReturnMetadataPatterns | AppRequestedEndpointList | ServerReturnedEndpointNonExistingPolicies | UserUpdatedEndpointListRefreshOptions; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts index 0fd970f4bed1..b4e00319485e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/endpoint_pagination.test.ts @@ -77,6 +77,7 @@ describe('endpoint list pagination: ', () => { expect(fakeHttpServices.post).toHaveBeenCalledWith('/api/endpoint/metadata', { body: JSON.stringify({ paging_properties: [{ page_index: '0' }, { page_size: '10' }], + filters: { kql: '' }, }), }); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/index.test.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/index.test.ts index 3a095644b3b4..f28ae9bf55ab 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/index.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/index.test.ts @@ -53,6 +53,8 @@ describe('EndpointList store concerns', () => { endpointPackageInfo: undefined, nonExistingPolicies: {}, endpointsExist: true, + patterns: [], + patternsError: undefined, isAutoRefreshEnabled: true, autoRefreshInterval: DEFAULT_POLL_INTERVAL, }); diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts index 15e89f977138..c4d2886f3e8e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.test.ts @@ -72,6 +72,7 @@ describe('endpoint list middleware', () => { expect(fakeHttpServices.post).toHaveBeenCalledWith('/api/endpoint/metadata', { body: JSON.stringify({ paging_properties: [{ page_index: '0' }, { page_size: '10' }], + filters: { kql: '' }, }), }); expect(listData(getState())).toEqual(apiResponse.hosts); @@ -100,6 +101,7 @@ describe('endpoint list middleware', () => { expect(fakeHttpServices.post).toHaveBeenCalledWith('/api/endpoint/metadata', { body: JSON.stringify({ paging_properties: [{ page_index: '0' }, { page_size: '10' }], + filters: { kql: '' }, }), }); expect(listData(getState())).toEqual(apiResponse.hosts); diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts index 2650aa486522..5bf085023c65 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts @@ -15,6 +15,8 @@ import { listData, endpointPackageInfo, nonExistingPolicies, + patterns, + searchBarQuery, } from './selectors'; import { EndpointState } from '../types'; import { @@ -23,8 +25,24 @@ import { sendGetAgentPolicyList, } from '../../policy/store/policy_list/services/ingest'; import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../../../../../ingest_manager/common'; +import { metadataCurrentIndexPattern } from '../../../../../common/endpoint/constants'; +import { IIndexPattern, Query } from '../../../../../../../../src/plugins/data/public'; -export const endpointMiddlewareFactory: ImmutableMiddlewareFactory = (coreStart) => { +export const endpointMiddlewareFactory: ImmutableMiddlewareFactory = ( + coreStart, + depsStart +) => { + async function fetchIndexPatterns(): Promise { + const { indexPatterns } = depsStart.data; + const fields = await indexPatterns.getFieldsForWildcard({ + pattern: metadataCurrentIndexPattern, + }); + const indexPattern: IIndexPattern = { + title: metadataCurrentIndexPattern, + fields, + }; + return [indexPattern]; + } // eslint-disable-next-line complexity return ({ getState, dispatch }) => (next) => async (action) => { next(action); @@ -52,10 +70,31 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory('/api/endpoint/metadata', { body: JSON.stringify({ paging_properties: [{ page_index: pageIndex }, { page_size: pageSize }], + filters: { kql: decodedQuery.query }, }), }); endpointResponse.request_page_index = Number(pageIndex); diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts index 060321fa4040..d688fa3b76b5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts @@ -31,6 +31,8 @@ export const initialEndpointListState: Immutable = { endpointPackageInfo: undefined, nonExistingPolicies: {}, endpointsExist: true, + patterns: [], + patternsError: undefined, isAutoRefreshEnabled: true, autoRefreshInterval: DEFAULT_POLL_INTERVAL, }; @@ -70,6 +72,18 @@ export const endpointListReducer: ImmutableReducer = ( ...action.payload, }, }; + } else if (action.type === 'serverReturnedMetadataPatterns') { + // handle error case + return { + ...state, + patterns: action.payload, + patternsError: undefined, + }; + } else if (action.type === 'serverFailedToReturnMetadataPatterns') { + return { + ...state, + patternsError: action.payload, + }; } else if (action.type === 'serverReturnedEndpointDetails') { return { ...state, diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts index 68ba71b7bbc9..8eefcc271794 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts @@ -8,6 +8,7 @@ import querystring from 'querystring'; import { createSelector } from 'reselect'; import { matchPath } from 'react-router-dom'; +import { decode } from 'rison-node'; import { Immutable, HostPolicyResponseAppliedAction, @@ -15,9 +16,13 @@ import { HostPolicyResponseActionStatus, } from '../../../../../common/endpoint/types'; import { EndpointState, EndpointIndexUIQueryParams } from '../types'; -import { MANAGEMENT_ROUTING_ENDPOINTS_PATH } from '../../../common/constants'; - -const PAGE_SIZES = Object.freeze([10, 20, 50]); +import { extractListPaginationParams } from '../../../common/routing'; +import { + MANAGEMENT_DEFAULT_PAGE, + MANAGEMENT_DEFAULT_PAGE_SIZE, + MANAGEMENT_ROUTING_ENDPOINTS_PATH, +} from '../../../common/constants'; +import { Query } from '../../../../../../../../src/plugins/data/common/query/types'; export const listData = (state: Immutable) => state.hosts; @@ -54,6 +59,13 @@ export const endpointPackageVersion = createSelector( (info) => info?.version ?? undefined ); +/** + * Returns the index patterns for the SearchBar to use for autosuggest + */ +export const patterns = (state: Immutable) => state.patterns; + +export const patternsError = (state: Immutable) => state.patternsError; + /** * Returns the full policy response from the endpoint after a user modifies a policy. */ @@ -129,16 +141,20 @@ export const uiQueryParams: ( ) => Immutable = createSelector( (state: Immutable) => state.location, (location: Immutable['location']) => { - const data: EndpointIndexUIQueryParams = { page_index: '0', page_size: '10' }; + const data: EndpointIndexUIQueryParams = { + page_index: String(MANAGEMENT_DEFAULT_PAGE), + page_size: String(MANAGEMENT_DEFAULT_PAGE_SIZE), + }; + if (location) { // Removes the `?` from the beginning of query string if it exists const query = querystring.parse(location.search.slice(1)); + const paginationParams = extractListPaginationParams(query); const keys: Array = [ 'selected_endpoint', - 'page_size', - 'page_index', 'show', + 'admin_query', ]; for (const key of keys) { @@ -160,17 +176,10 @@ export const uiQueryParams: ( } } - // Check if page size is an expected size, otherwise default to 10 - if (!PAGE_SIZES.includes(Number(data.page_size))) { - data.page_size = '10'; - } - - // Check if page index is a valid positive integer, otherwise default to 0 - const pageIndexAsNumber = Number(data.page_index); - if (!Number.isFinite(pageIndexAsNumber) || pageIndexAsNumber < 0) { - data.page_index = '0'; - } + data.page_size = String(paginationParams.page_size); + data.page_index = String(paginationParams.page_index); } + return data; } ); @@ -214,3 +223,27 @@ export const nonExistingPolicies: ( */ export const endpointsExist: (state: Immutable) => boolean = (state) => state.endpointsExist; + +/** + * Returns query text from query bar + */ +export const searchBarQuery: (state: Immutable) => Query = createSelector( + uiQueryParams, + ({ admin_query: adminQuery }) => { + const decodedQuery: Query = { query: '', language: 'kuery' }; + if (adminQuery) { + const urlDecodedQuery = (decode(adminQuery) as unknown) as Query; + if (urlDecodedQuery && typeof urlDecodedQuery.query === 'string') { + decodedQuery.query = urlDecodedQuery.query; + } + if ( + urlDecodedQuery && + typeof urlDecodedQuery.language === 'string' && + (urlDecodedQuery.language === 'kuery' || urlDecodedQuery.language === 'lucene') + ) { + decodedQuery.language = urlDecodedQuery.language; + } + } + return decodedQuery; + } +); diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts index 5a6a1af7bd7e..b73e60718d12 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts @@ -14,6 +14,7 @@ import { } from '../../../../common/endpoint/types'; import { ServerApiError } from '../../../common/types'; import { GetPackagesResponse } from '../../../../../ingest_manager/common'; +import { IIndexPattern } from '../../../../../../../src/plugins/data/public'; export interface EndpointState { /** list of host **/ @@ -54,6 +55,10 @@ export interface EndpointState { nonExistingPolicies: Record; /** Tracks whether hosts exist and helps control if onboarding should be visible */ endpointsExist: boolean; + /** index patterns for query bar */ + patterns: IIndexPattern[]; + /** api error from retrieving index patters for query bar */ + patternsError?: ServerApiError; /** Is auto-refresh enabled */ isAutoRefreshEnabled: boolean; /** The current auto refresh interval for data in ms */ @@ -72,4 +77,6 @@ export interface EndpointIndexUIQueryParams { page_index?: string; /** show the policy response or host details */ show?: 'policy_response' | 'details'; + /** Query text from search bar*/ + admin_query?: string; } diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/search_bar.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/search_bar.tsx new file mode 100644 index 000000000000..b6349a45f383 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/components/search_bar.tsx @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { memo, useCallback, useMemo } from 'react'; +import { useHistory } from 'react-router-dom'; +import { encode, RisonValue } from 'rison-node'; +import styled from 'styled-components'; +import { Query, SearchBar, TimeHistory } from '../../../../../../../../../src/plugins/data/public'; +import { Storage } from '../../../../../../../../../src/plugins/kibana_utils/public'; +import { urlFromQueryParams } from '../url_from_query_params'; +import { useEndpointSelector } from '../hooks'; +import * as selectors from '../../store/selectors'; +import { clone } from '../../models/index_pattern'; + +const AdminQueryBar = styled.div` + .globalQueryBar { + padding: 0; + } +`; + +export const AdminSearchBar = memo(() => { + const history = useHistory(); + const queryParams = useEndpointSelector(selectors.uiQueryParams); + const searchBarIndexPatterns = useEndpointSelector(selectors.patterns); + const searchBarQuery = useEndpointSelector(selectors.searchBarQuery); + const clonedIndexPatterns = useMemo( + () => searchBarIndexPatterns.map((pattern) => clone(pattern)), + [searchBarIndexPatterns] + ); + + const onQuerySubmit = useCallback( + (params: { query?: Query }) => { + history.push( + urlFromQueryParams({ + ...queryParams, + admin_query: encode((params.query as unknown) as RisonValue), + }) + ); + }, + [history, queryParams] + ); + + const timeHistory = useMemo(() => new TimeHistory(new Storage(localStorage)), []); + + return ( +
+ {searchBarIndexPatterns && searchBarIndexPatterns.length > 0 && ( + + + + )} +
+ ); +}); + +AdminSearchBar.displayName = 'AdminSearchBar'; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx index 8d08ac4e59a8..378f3cc4cb31 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx @@ -16,6 +16,8 @@ import { EuiSelectableProps, EuiSuperDatePicker, EuiSpacer, + EuiFlexGroup, + EuiFlexItem, } from '@elastic/eui'; import { useHistory } from 'react-router-dom'; import { i18n } from '@kbn/i18n'; @@ -33,7 +35,7 @@ import { import { useNavigateByRouterEventHandler } from '../../../../common/hooks/endpoint/use_navigate_by_router_event_handler'; import { CreateStructuredSelector } from '../../../../common/store'; import { Immutable, HostInfo } from '../../../../../common/endpoint/types'; -import { DEFAULT_POLL_INTERVAL } from '../../../common/constants'; +import { DEFAULT_POLL_INTERVAL, MANAGEMENT_PAGE_SIZE_OPTIONS } from '../../../common/constants'; import { PolicyEmptyState, HostsEmptyState } from '../../../components/management_empty_state'; import { FormattedDate } from '../../../../common/components/formatted_date'; import { useNavigateToAppEventHandler } from '../../../../common/hooks/endpoint/use_navigate_to_app_event_handler'; @@ -46,6 +48,7 @@ import { getEndpointListPath, getEndpointDetailsPath } from '../../../common/rou import { useFormatUrl } from '../../../../common/components/link_to'; import { EndpointAction } from '../store/action'; import { EndpointPolicyLink } from './components/endpoint_policy_link'; +import { AdminSearchBar } from './components/search_bar'; import { AdministrationListPage } from '../../../components/administration_list_page'; const EndpointListNavLink = memo<{ @@ -89,6 +92,7 @@ export const EndpointList = () => { endpointsExist, autoRefreshInterval, isAutoRefreshEnabled, + patternsError, } = useEndpointSelector(selector); const { formatUrl, search } = useFormatUrl(SecurityPageName.administration); @@ -99,7 +103,7 @@ export const EndpointList = () => { pageIndex, pageSize, totalItemCount, - pageSizeOptions: [10, 20, 50], + pageSizeOptions: [...MANAGEMENT_PAGE_SIZE_OPTIONS], hidePerPageOptions: false, }; }, [pageIndex, pageSize, totalItemCount]); @@ -397,16 +401,16 @@ export const EndpointList = () => { const hasListData = listData && listData.length > 0; const refreshStyle = useMemo(() => { - return { display: hasListData ? 'flex' : 'none', maxWidth: 200 }; - }, [hasListData]); + return { display: endpointsExist ? 'flex' : 'none', maxWidth: 200 }; + }, [endpointsExist]); const refreshIsPaused = useMemo(() => { - return !hasListData ? false : hasSelectedEndpoint ? true : !isAutoRefreshEnabled; - }, [hasListData, hasSelectedEndpoint, isAutoRefreshEnabled]); + return !endpointsExist ? false : hasSelectedEndpoint ? true : !isAutoRefreshEnabled; + }, [endpointsExist, hasSelectedEndpoint, isAutoRefreshEnabled]); const refreshInterval = useMemo(() => { - return !hasListData ? DEFAULT_POLL_INTERVAL : autoRefreshInterval; - }, [hasListData, autoRefreshInterval]); + return !endpointsExist ? DEFAULT_POLL_INTERVAL : autoRefreshInterval; + }, [endpointsExist, autoRefreshInterval]); return ( { } > {hasSelectedEndpoint && } - { - <> -
+ <> + + {endpointsExist && !patternsError && ( + + + + )} + { onRefreshChange={onRefreshChange} isAutoRefreshOnly={true} /> -
- - - } +
+
+ + {hasListData && ( <> diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts new file mode 100644 index 000000000000..9308c137cfb9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/service/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { HttpStart } from 'kibana/public'; +import { TRUSTED_APPS_LIST_API } from '../../../../../common/endpoint/constants'; +import { + GetTrustedListAppsResponse, + GetTrustedAppsListRequest, +} from '../../../../../common/endpoint/types/trusted_apps'; + +export interface TrustedAppsService { + getTrustedAppsList(request: GetTrustedAppsListRequest): Promise; +} + +export class TrustedAppsHttpService implements TrustedAppsService { + constructor(private http: HttpStart) {} + + async getTrustedAppsList(request: GetTrustedAppsListRequest) { + return this.http.get(TRUSTED_APPS_LIST_API, { + query: request, + }); + } +} diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/async_resource_state.test.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/async_resource_state.test.ts new file mode 100644 index 000000000000..5e00d833981e --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/async_resource_state.test.ts @@ -0,0 +1,242 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + UninitialisedResourceState, + LoadingResourceState, + LoadedResourceState, + FailedResourceState, + isUninitialisedResourceState, + isLoadingResourceState, + isLoadedResourceState, + isFailedResourceState, + getLastLoadedResourceState, + getCurrentResourceError, + isOutdatedResourceState, +} from './async_resource_state'; + +interface TestData { + property: string; +} + +const data: TestData = { property: 'value' }; + +const uninitialisedResourceState: UninitialisedResourceState = { + type: 'UninitialisedResourceState', +}; + +const loadedResourceState: LoadedResourceState = { + type: 'LoadedResourceState', + data, +}; + +const failedResourceStateInitially: FailedResourceState = { + type: 'FailedResourceState', + error: {}, +}; + +const failedResourceStateSubsequently: FailedResourceState = { + type: 'FailedResourceState', + error: {}, + lastLoadedState: loadedResourceState, +}; + +const loadingResourceStateInitially: LoadingResourceState = { + type: 'LoadingResourceState', + previousState: uninitialisedResourceState, +}; + +const loadingResourceStateAfterSuccess: LoadingResourceState = { + type: 'LoadingResourceState', + previousState: loadedResourceState, +}; + +const loadingResourceStateAfterInitialFailure: LoadingResourceState = { + type: 'LoadingResourceState', + previousState: failedResourceStateInitially, +}; + +const loadingResourceStateAfterSubsequentFailure: LoadingResourceState = { + type: 'LoadingResourceState', + previousState: failedResourceStateSubsequently, +}; + +describe('AsyncResourceState', () => { + describe('guards', () => { + describe('isUninitialisedResourceState()', () => { + it('returns true for UninitialisedResourceState', () => { + expect(isUninitialisedResourceState(uninitialisedResourceState)).toBe(true); + }); + + it('returns false for LoadingResourceState', () => { + expect(isUninitialisedResourceState(loadingResourceStateInitially)).toBe(false); + }); + + it('returns false for LoadedResourceState', () => { + expect(isUninitialisedResourceState(loadedResourceState)).toBe(false); + }); + + it('returns false for FailedResourceState', () => { + expect(isUninitialisedResourceState(failedResourceStateInitially)).toBe(false); + }); + }); + + describe('isLoadingResourceState()', () => { + it('returns false for UninitialisedResourceState', () => { + expect(isLoadingResourceState(uninitialisedResourceState)).toBe(false); + }); + + it('returns true for LoadingResourceState', () => { + expect(isLoadingResourceState(loadingResourceStateInitially)).toBe(true); + }); + + it('returns false for LoadedResourceState', () => { + expect(isLoadingResourceState(loadedResourceState)).toBe(false); + }); + + it('returns false for FailedResourceState', () => { + expect(isLoadingResourceState(failedResourceStateInitially)).toBe(false); + }); + }); + + describe('isLoadedResourceState()', () => { + it('returns false for UninitialisedResourceState', () => { + expect(isLoadedResourceState(uninitialisedResourceState)).toBe(false); + }); + + it('returns false for LoadingResourceState', () => { + expect(isLoadedResourceState(loadingResourceStateInitially)).toBe(false); + }); + + it('returns true for LoadedResourceState', () => { + expect(isLoadedResourceState(loadedResourceState)).toBe(true); + }); + + it('returns false for FailedResourceState', () => { + expect(isLoadedResourceState(failedResourceStateInitially)).toBe(false); + }); + }); + + describe('isFailedResourceState()', () => { + it('returns false for UninitialisedResourceState', () => { + expect(isFailedResourceState(uninitialisedResourceState)).toBe(false); + }); + + it('returns false for LoadingResourceState', () => { + expect(isFailedResourceState(loadingResourceStateInitially)).toBe(false); + }); + + it('returns false for LoadedResourceState', () => { + expect(isFailedResourceState(loadedResourceState)).toBe(false); + }); + + it('returns true for FailedResourceState', () => { + expect(isFailedResourceState(failedResourceStateInitially)).toBe(true); + }); + }); + }); + + describe('functions', () => { + describe('getLastLoadedResourceState()', () => { + it('returns undefined for UninitialisedResourceState', () => { + expect(getLastLoadedResourceState(uninitialisedResourceState)).toBeUndefined(); + }); + + it('returns current state for LoadedResourceState', () => { + expect(getLastLoadedResourceState(loadedResourceState)).toBe(loadedResourceState); + }); + + it('returns undefined for initial FailedResourceState', () => { + expect(getLastLoadedResourceState(failedResourceStateInitially)).toBeUndefined(); + }); + + it('returns last loaded state for subsequent FailedResourceState', () => { + expect(getLastLoadedResourceState(failedResourceStateSubsequently)).toBe( + loadedResourceState + ); + }); + + it('returns undefined for initial LoadingResourceState', () => { + expect(getLastLoadedResourceState(loadingResourceStateInitially)).toBeUndefined(); + }); + + it('returns previous state for LoadingResourceState after success', () => { + expect(getLastLoadedResourceState(loadingResourceStateAfterSuccess)).toBe( + loadedResourceState + ); + }); + + it('returns undefined for LoadingResourceState after initial failure', () => { + expect(getLastLoadedResourceState(loadingResourceStateAfterInitialFailure)).toBeUndefined(); + }); + + it('returns previous state for LoadingResourceState after subsequent failure', () => { + expect(getLastLoadedResourceState(loadingResourceStateAfterSubsequentFailure)).toBe( + loadedResourceState + ); + }); + }); + + describe('getCurrentResourceError()', () => { + it('returns undefined for UninitialisedResourceState', () => { + expect(getCurrentResourceError(uninitialisedResourceState)).toBeUndefined(); + }); + + it('returns undefined for LoadedResourceState', () => { + expect(getCurrentResourceError(loadedResourceState)).toBeUndefined(); + }); + + it('returns error for FailedResourceState', () => { + expect(getCurrentResourceError(failedResourceStateSubsequently)).toStrictEqual({}); + }); + + it('returns undefined for LoadingResourceState', () => { + expect(getCurrentResourceError(loadingResourceStateAfterSubsequentFailure)).toBeUndefined(); + }); + }); + + describe('isOutdatedResourceState()', () => { + const trueFreshnessTest = (testData: TestData) => true; + const falseFreshnessTest = (testData: TestData) => false; + + it('returns true for UninitialisedResourceState', () => { + expect(isOutdatedResourceState(uninitialisedResourceState, falseFreshnessTest)).toBe(true); + }); + + it('returns false for LoadingResourceState', () => { + expect(isOutdatedResourceState(loadingResourceStateAfterSuccess, falseFreshnessTest)).toBe( + false + ); + }); + + it('returns false for LoadedResourceState and fresh data', () => { + expect(isOutdatedResourceState(loadedResourceState, trueFreshnessTest)).toBe(false); + }); + + it('returns true for LoadedResourceState and outdated data', () => { + expect(isOutdatedResourceState(loadedResourceState, falseFreshnessTest)).toBe(true); + }); + + it('returns true for initial FailedResourceState', () => { + expect(isOutdatedResourceState(failedResourceStateInitially, falseFreshnessTest)).toBe( + true + ); + }); + + it('returns false for subsequent FailedResourceState and fresh data', () => { + expect(isOutdatedResourceState(failedResourceStateSubsequently, trueFreshnessTest)).toBe( + false + ); + }); + + it('returns true for subsequent FailedResourceState and outdated data', () => { + expect(isOutdatedResourceState(failedResourceStateSubsequently, falseFreshnessTest)).toBe( + true + ); + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/async_resource_state.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/async_resource_state.ts new file mode 100644 index 000000000000..4639a50a6186 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/async_resource_state.ts @@ -0,0 +1,138 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/* + * this file contains set of types to represent state of asynchronous resource. + * Resource is defined as a reference to potential data that is loaded/updated + * using asynchronous communication with data source (for example through REST API call). + * Asynchronous update implies that next to just having data: + * - there is moment in time when data is not loaded/initialised and not in process of loading/updating + * - process performing data update can take considerable time which needs to be communicated to user + * - update can fail due to multiple reasons and also needs to be communicated to the user + */ + +import { Immutable } from '../../../../../common/endpoint/types'; +import { ServerApiError } from '../../../../common/types'; + +/** + * Data type to represent uninitialised state of asynchronous resource. + * This state indicates that no actions to load the data has be taken. + */ +export interface UninitialisedResourceState { + type: 'UninitialisedResourceState'; +} + +/** + * Data type to represent loading state of asynchronous resource. Loading state + * should be used to indicate that data is in the process of loading/updating. + * It contains reference to previous stale state that can be used to present + * previous state of resource to the user (like show previous already loaded + * data or show previous failure). + * + * @param Data - type of the data that is referenced by resource state + * @param Error - type of the error that can happen during attempt to update data + */ +export interface LoadingResourceState { + type: 'LoadingResourceState'; + previousState: StaleResourceState; +} + +/** + * Data type to represent loaded state of asynchronous resource. Loaded state + * is characterised with reference to the loaded data. + * + * @param Data - type of the data that is referenced by resource state + */ +export interface LoadedResourceState { + type: 'LoadedResourceState'; + data: Data; +} + +/** + * Data type to represent failed state of asynchronous resource. Failed state + * is characterised with error and can reference last loaded state. Reference + * to last loaded state can be used to present previous successfully loaded data. + * + * @param Data - type of the data that is referenced by resource state + * @param Error - type of the error that can happen during attempt to update data + */ +export interface FailedResourceState { + type: 'FailedResourceState'; + error: Error; + lastLoadedState?: LoadedResourceState; +} + +/** + * Data type to represent stale (not loading) state of asynchronous resource. + * + * @param Data - type of the data that is referenced by resource state + * @param Error - type of the error that can happen during attempt to update data + */ +export type StaleResourceState = + | UninitialisedResourceState + | LoadedResourceState + | FailedResourceState; + +/** + * Data type to represent any state of asynchronous resource. + * + * @param Data - type of the data that is referenced by resource state + * @param Error - type of the error that can happen during attempt to update data + */ +export type AsyncResourceState = + | UninitialisedResourceState + | LoadingResourceState + | LoadedResourceState + | FailedResourceState; + +// Set of guards to narrow the type of AsyncResourceState that make further refactoring easier + +export const isUninitialisedResourceState = ( + state: Immutable> +): state is Immutable => state.type === 'UninitialisedResourceState'; + +export const isLoadingResourceState = ( + state: Immutable> +): state is Immutable> => state.type === 'LoadingResourceState'; + +export const isLoadedResourceState = ( + state: Immutable> +): state is Immutable> => state.type === 'LoadedResourceState'; + +export const isFailedResourceState = ( + state: Immutable> +): state is Immutable> => state.type === 'FailedResourceState'; + +// Set of functions to work with AsyncResourceState + +export const getLastLoadedResourceState = ( + state: Immutable> +): Immutable> | undefined => { + if (isLoadedResourceState(state)) { + return state; + } else if (isLoadingResourceState(state)) { + return getLastLoadedResourceState(state.previousState); + } else if (isFailedResourceState(state)) { + return state.lastLoadedState; + } else { + return undefined; + } +}; + +export const getCurrentResourceError = ( + state: Immutable> +): Immutable | undefined => { + return isFailedResourceState(state) ? state.error : undefined; +}; + +export const isOutdatedResourceState = ( + state: AsyncResourceState, + isFresh: (data: Data) => boolean +): boolean => + isUninitialisedResourceState(state) || + (isLoadedResourceState(state) && !isFresh(state.data)) || + (isFailedResourceState(state) && + (!state.lastLoadedState || !isFresh(state.lastLoadedState.data))); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/index.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/index.ts new file mode 100644 index 000000000000..99bdac57da4b --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export * from './async_resource_state'; +export * from './trusted_apps_list_page_state'; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/trusted_apps_list_page_state.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/trusted_apps_list_page_state.ts new file mode 100644 index 000000000000..23f4cfd576c5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/state/trusted_apps_list_page_state.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { TrustedApp } from '../../../../../common/endpoint/types/trusted_apps'; +import { AsyncResourceState } from '.'; + +export interface PaginationInfo { + index: number; + size: number; +} + +export interface TrustedAppsListData { + items: TrustedApp[]; + totalItemsCount: number; + paginationInfo: PaginationInfo; +} + +export interface TrustedAppsListPageState { + listView: { + currentListResourceState: AsyncResourceState; + currentPaginationInfo: PaginationInfo; + }; + active: boolean; +} diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/action.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/action.ts new file mode 100644 index 000000000000..2154a0eca462 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/action.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { AsyncResourceState, TrustedAppsListData } from '../state'; + +export interface TrustedAppsListResourceStateChanged { + type: 'trustedAppsListResourceStateChanged'; + payload: { + newState: AsyncResourceState; + }; +} + +export type TrustedAppsPageAction = TrustedAppsListResourceStateChanged; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/middleware.test.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/middleware.test.ts new file mode 100644 index 000000000000..c5abaae47348 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/middleware.test.ts @@ -0,0 +1,130 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { applyMiddleware, createStore } from 'redux'; + +import { createSpyMiddleware } from '../../../../common/store/test_utils'; + +import { + createFailedListViewWithPagination, + createLoadedListViewWithPagination, + createLoadingListViewWithPagination, + createSampleTrustedApps, + createServerApiError, + createUserChangedUrlAction, +} from '../test_utils'; + +import { TrustedAppsService } from '../service'; +import { PaginationInfo, TrustedAppsListPageState } from '../state'; +import { initialTrustedAppsPageState, trustedAppsPageReducer } from './reducer'; +import { createTrustedAppsPageMiddleware } from './middleware'; + +const createGetTrustedListAppsResponse = (pagination: PaginationInfo, totalItemsCount: number) => ({ + data: createSampleTrustedApps(pagination), + page: pagination.index, + per_page: pagination.size, + total: totalItemsCount, +}); + +const createTrustedAppsServiceMock = (): jest.Mocked => ({ + getTrustedAppsList: jest.fn(), +}); + +const createStoreSetup = (trustedAppsService: TrustedAppsService) => { + const spyMiddleware = createSpyMiddleware(); + + return { + spyMiddleware, + store: createStore( + trustedAppsPageReducer, + applyMiddleware( + createTrustedAppsPageMiddleware(trustedAppsService), + spyMiddleware.actionSpyMiddleware + ) + ), + }; +}; + +describe('middleware', () => { + describe('refreshing list resource state', () => { + it('sets initial state properly', async () => { + expect(createStoreSetup(createTrustedAppsServiceMock()).store.getState()).toStrictEqual( + initialTrustedAppsPageState + ); + }); + + it('refreshes the list when location changes and data gets outdated', async () => { + const pagination = { index: 2, size: 50 }; + const service = createTrustedAppsServiceMock(); + const { store, spyMiddleware } = createStoreSetup(service); + + service.getTrustedAppsList.mockResolvedValue( + createGetTrustedListAppsResponse(pagination, 500) + ); + + store.dispatch(createUserChangedUrlAction('/trusted_apps', '?page_index=2&page_size=50')); + + expect(store.getState()).toStrictEqual({ + listView: createLoadingListViewWithPagination(pagination), + active: true, + }); + + await spyMiddleware.waitForAction('trustedAppsListResourceStateChanged'); + + expect(store.getState()).toStrictEqual({ + listView: createLoadedListViewWithPagination(pagination, pagination, 500), + active: true, + }); + }); + + it('does not refresh the list when location changes and data does not get outdated', async () => { + const pagination = { index: 2, size: 50 }; + const service = createTrustedAppsServiceMock(); + const { store, spyMiddleware } = createStoreSetup(service); + + service.getTrustedAppsList.mockResolvedValue( + createGetTrustedListAppsResponse(pagination, 500) + ); + + store.dispatch(createUserChangedUrlAction('/trusted_apps', '?page_index=2&page_size=50')); + + await spyMiddleware.waitForAction('trustedAppsListResourceStateChanged'); + + store.dispatch(createUserChangedUrlAction('/trusted_apps', '?page_index=2&page_size=50')); + + expect(service.getTrustedAppsList).toBeCalledTimes(1); + expect(store.getState()).toStrictEqual({ + listView: createLoadedListViewWithPagination(pagination, pagination, 500), + active: true, + }); + }); + + it('set list resource state to faile when failing to load data', async () => { + const service = createTrustedAppsServiceMock(); + const { store, spyMiddleware } = createStoreSetup(service); + + service.getTrustedAppsList.mockRejectedValue(createServerApiError('Internal Server Error')); + + store.dispatch(createUserChangedUrlAction('/trusted_apps', '?page_index=2&page_size=50')); + + await spyMiddleware.waitForAction('trustedAppsListResourceStateChanged'); + + expect(store.getState()).toStrictEqual({ + listView: createFailedListViewWithPagination( + { index: 2, size: 50 }, + createServerApiError('Internal Server Error') + ), + active: true, + }); + + const infiniteLoopTest = async () => { + await spyMiddleware.waitForAction('trustedAppsListResourceStateChanged'); + }; + + await expect(infiniteLoopTest).rejects.not.toBeNull(); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/middleware.ts new file mode 100644 index 000000000000..31c301b8dbd2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/middleware.ts @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Immutable } from '../../../../../common/endpoint/types'; +import { AppAction } from '../../../../common/store/actions'; +import { + ImmutableMiddleware, + ImmutableMiddlewareAPI, + ImmutableMiddlewareFactory, +} from '../../../../common/store'; + +import { TrustedAppsHttpService, TrustedAppsService } from '../service'; + +import { + AsyncResourceState, + StaleResourceState, + TrustedAppsListData, + TrustedAppsListPageState, +} from '../state'; + +import { TrustedAppsListResourceStateChanged } from './action'; + +import { + getCurrentListResourceState, + getLastLoadedListResourceState, + getListCurrentPageIndex, + getListCurrentPageSize, + needsRefreshOfListData, +} from './selectors'; + +const createTrustedAppsListResourceStateChangedAction = ( + newState: Immutable> +): Immutable => ({ + type: 'trustedAppsListResourceStateChanged', + payload: { newState }, +}); + +const refreshList = async ( + store: ImmutableMiddlewareAPI, + trustedAppsService: TrustedAppsService +) => { + store.dispatch( + createTrustedAppsListResourceStateChangedAction({ + type: 'LoadingResourceState', + // need to think on how to avoid the casting + previousState: getCurrentListResourceState(store.getState()) as Immutable< + StaleResourceState + >, + }) + ); + + try { + const pageIndex = getListCurrentPageIndex(store.getState()); + const pageSize = getListCurrentPageSize(store.getState()); + const response = await trustedAppsService.getTrustedAppsList({ + page: pageIndex + 1, + per_page: pageSize, + }); + + store.dispatch( + createTrustedAppsListResourceStateChangedAction({ + type: 'LoadedResourceState', + data: { + items: response.data, + totalItemsCount: response.total, + paginationInfo: { index: pageIndex, size: pageSize }, + }, + }) + ); + } catch (error) { + store.dispatch( + createTrustedAppsListResourceStateChangedAction({ + type: 'FailedResourceState', + error, + lastLoadedState: getLastLoadedListResourceState(store.getState()), + }) + ); + } +}; + +export const createTrustedAppsPageMiddleware = ( + trustedAppsService: TrustedAppsService +): ImmutableMiddleware => { + return (store) => (next) => async (action) => { + next(action); + + // TODO: need to think if failed state is a good condition to consider need for refresh + if (action.type === 'userChangedUrl' && needsRefreshOfListData(store.getState())) { + await refreshList(store, trustedAppsService); + } + }; +}; + +export const trustedAppsPageMiddlewareFactory: ImmutableMiddlewareFactory = ( + coreStart +) => createTrustedAppsPageMiddleware(new TrustedAppsHttpService(coreStart.http)); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/reducer.test.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/reducer.test.ts new file mode 100644 index 000000000000..34325e0cf139 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/reducer.test.ts @@ -0,0 +1,95 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { initialTrustedAppsPageState, trustedAppsPageReducer } from './reducer'; +import { + createListLoadedResourceState, + createLoadedListViewWithPagination, + createTrustedAppsListResourceStateChangedAction, + createUserChangedUrlAction, +} from '../test_utils'; + +describe('reducer', () => { + describe('UserChangedUrl', () => { + it('makes page state active and extracts pagination parameters', () => { + const result = trustedAppsPageReducer( + initialTrustedAppsPageState, + createUserChangedUrlAction('/trusted_apps', '?page_index=5&page_size=50') + ); + + expect(result).toStrictEqual({ + listView: { + ...initialTrustedAppsPageState.listView, + currentPaginationInfo: { index: 5, size: 50 }, + }, + active: true, + }); + }); + + it('extracts default pagination parameters when none provided', () => { + const result = trustedAppsPageReducer( + { + ...initialTrustedAppsPageState, + listView: { + ...initialTrustedAppsPageState.listView, + currentPaginationInfo: { index: 5, size: 50 }, + }, + }, + createUserChangedUrlAction('/trusted_apps', '?page_index=b&page_size=60') + ); + + expect(result).toStrictEqual({ + ...initialTrustedAppsPageState, + active: true, + }); + }); + + it('extracts default pagination parameters when invalid provided', () => { + const result = trustedAppsPageReducer( + { + ...initialTrustedAppsPageState, + listView: { + ...initialTrustedAppsPageState.listView, + currentPaginationInfo: { index: 5, size: 50 }, + }, + }, + createUserChangedUrlAction('/trusted_apps') + ); + + expect(result).toStrictEqual({ + ...initialTrustedAppsPageState, + active: true, + }); + }); + + it('makes page state inactive and resets list to uninitialised state when navigating away', () => { + const result = trustedAppsPageReducer( + { listView: createLoadedListViewWithPagination(), active: true }, + createUserChangedUrlAction('/endpoints') + ); + + expect(result).toStrictEqual(initialTrustedAppsPageState); + }); + }); + + describe('TrustedAppsListResourceStateChanged', () => { + it('sets the current list resource state', () => { + const listResourceState = createListLoadedResourceState({ index: 3, size: 50 }, 200); + const result = trustedAppsPageReducer( + initialTrustedAppsPageState, + createTrustedAppsListResourceStateChangedAction(listResourceState) + ); + + expect(result).toStrictEqual({ + ...initialTrustedAppsPageState, + listView: { + ...initialTrustedAppsPageState.listView, + currentListResourceState: listResourceState, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/reducer.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/reducer.ts new file mode 100644 index 000000000000..4fdc6f90ef40 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/reducer.ts @@ -0,0 +1,96 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +// eslint-disable-next-line import/no-nodejs-modules +import { parse } from 'querystring'; +import { matchPath } from 'react-router-dom'; +import { ImmutableReducer } from '../../../../common/store'; +import { AppLocation, Immutable } from '../../../../../common/endpoint/types'; +import { UserChangedUrl } from '../../../../common/store/routing/action'; +import { AppAction } from '../../../../common/store/actions'; +import { extractListPaginationParams } from '../../../common/routing'; +import { + MANAGEMENT_ROUTING_TRUSTED_APPS_PATH, + MANAGEMENT_DEFAULT_PAGE, + MANAGEMENT_DEFAULT_PAGE_SIZE, +} from '../../../common/constants'; + +import { TrustedAppsListResourceStateChanged } from './action'; +import { TrustedAppsListPageState } from '../state'; + +type StateReducer = ImmutableReducer; +type CaseReducer = ( + state: Immutable, + action: Immutable +) => Immutable; + +const isTrustedAppsPageLocation = (location: Immutable) => { + return ( + matchPath(location.pathname ?? '', { + path: MANAGEMENT_ROUTING_TRUSTED_APPS_PATH, + exact: true, + }) !== null + ); +}; + +const trustedAppsListResourceStateChanged: CaseReducer = ( + state, + action +) => { + return { + ...state, + listView: { + ...state.listView, + currentListResourceState: action.payload.newState, + }, + }; +}; + +const userChangedUrl: CaseReducer = (state, action) => { + if (isTrustedAppsPageLocation(action.payload)) { + const paginationParams = extractListPaginationParams(parse(action.payload.search.slice(1))); + + return { + ...state, + listView: { + ...state.listView, + currentPaginationInfo: { + index: paginationParams.page_index, + size: paginationParams.page_size, + }, + }, + active: true, + }; + } else { + return initialTrustedAppsPageState; + } +}; + +export const initialTrustedAppsPageState: TrustedAppsListPageState = { + listView: { + currentListResourceState: { type: 'UninitialisedResourceState' }, + currentPaginationInfo: { + index: MANAGEMENT_DEFAULT_PAGE, + size: MANAGEMENT_DEFAULT_PAGE_SIZE, + }, + }, + active: false, +}; + +export const trustedAppsPageReducer: StateReducer = ( + state = initialTrustedAppsPageState, + action +) => { + switch (action.type) { + case 'trustedAppsListResourceStateChanged': + return trustedAppsListResourceStateChanged(state, action); + + case 'userChangedUrl': + return userChangedUrl(state, action); + } + + return state; +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/selectors.test.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/selectors.test.ts new file mode 100644 index 000000000000..a969e2dee477 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/selectors.test.ts @@ -0,0 +1,179 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + getCurrentListResourceState, + getLastLoadedListResourceState, + getListCurrentPageIndex, + getListCurrentPageSize, + getListErrorMessage, + getListItems, + getListTotalItemsCount, + isListLoading, + needsRefreshOfListData, +} from './selectors'; + +import { + createDefaultListView, + createDefaultPaginationInfo, + createListComplexLoadingResourceState, + createListFailedResourceState, + createListLoadedResourceState, + createLoadedListViewWithPagination, + createSampleTrustedApps, + createUninitialisedResourceState, +} from '../test_utils'; + +describe('selectors', () => { + describe('needsRefreshOfListData()', () => { + it('returns false for outdated resource state and inactive state', () => { + expect(needsRefreshOfListData({ listView: createDefaultListView(), active: false })).toBe( + false + ); + }); + + it('returns true for outdated resource state and active state', () => { + expect(needsRefreshOfListData({ listView: createDefaultListView(), active: true })).toBe( + true + ); + }); + + it('returns true when current loaded page index is outdated', () => { + const listView = createLoadedListViewWithPagination({ index: 1, size: 20 }); + + expect(needsRefreshOfListData({ listView, active: true })).toBe(true); + }); + + it('returns true when current loaded page size is outdated', () => { + const listView = createLoadedListViewWithPagination({ index: 0, size: 50 }); + + expect(needsRefreshOfListData({ listView, active: true })).toBe(true); + }); + + it('returns false when current loaded data is up to date', () => { + const listView = createLoadedListViewWithPagination(); + + expect(needsRefreshOfListData({ listView, active: true })).toBe(false); + }); + }); + + describe('getCurrentListResourceState()', () => { + it('returns current list resource state', () => { + const listView = createDefaultListView(); + + expect(getCurrentListResourceState({ listView, active: false })).toStrictEqual( + createUninitialisedResourceState() + ); + }); + }); + + describe('getLastLoadedListResourceState()', () => { + it('returns last loaded list resource state', () => { + const listView = { + currentListResourceState: createListComplexLoadingResourceState( + createDefaultPaginationInfo(), + 200 + ), + currentPaginationInfo: createDefaultPaginationInfo(), + }; + + expect(getLastLoadedListResourceState({ listView, active: false })).toStrictEqual( + createListLoadedResourceState(createDefaultPaginationInfo(), 200) + ); + }); + }); + + describe('getListItems()', () => { + it('returns empty list when no valid data loaded', () => { + expect(getListItems({ listView: createDefaultListView(), active: false })).toStrictEqual([]); + }); + + it('returns last loaded list items', () => { + const listView = { + currentListResourceState: createListComplexLoadingResourceState( + createDefaultPaginationInfo(), + 200 + ), + currentPaginationInfo: createDefaultPaginationInfo(), + }; + + expect(getListItems({ listView, active: false })).toStrictEqual( + createSampleTrustedApps(createDefaultPaginationInfo()) + ); + }); + }); + + describe('getListTotalItemsCount()', () => { + it('returns 0 when no valid data loaded', () => { + expect(getListTotalItemsCount({ listView: createDefaultListView(), active: false })).toBe(0); + }); + + it('returns last loaded total items count', () => { + const listView = { + currentListResourceState: createListComplexLoadingResourceState( + createDefaultPaginationInfo(), + 200 + ), + currentPaginationInfo: createDefaultPaginationInfo(), + }; + + expect(getListTotalItemsCount({ listView, active: false })).toBe(200); + }); + }); + + describe('getListCurrentPageIndex()', () => { + it('returns page index', () => { + expect(getListCurrentPageIndex({ listView: createDefaultListView(), active: false })).toBe(0); + }); + }); + + describe('getListCurrentPageSize()', () => { + it('returns page index', () => { + expect(getListCurrentPageSize({ listView: createDefaultListView(), active: false })).toBe(20); + }); + }); + + describe('getListErrorMessage()', () => { + it('returns undefined when not in failed state', () => { + const listView = { + currentListResourceState: createListComplexLoadingResourceState( + createDefaultPaginationInfo(), + 200 + ), + currentPaginationInfo: createDefaultPaginationInfo(), + }; + + expect(getListErrorMessage({ listView, active: false })).toBeUndefined(); + }); + + it('returns message when not in failed state', () => { + const listView = { + currentListResourceState: createListFailedResourceState('Internal Server Error'), + currentPaginationInfo: createDefaultPaginationInfo(), + }; + + expect(getListErrorMessage({ listView, active: false })).toBe('Internal Server Error'); + }); + }); + + describe('isListLoading()', () => { + it('returns false when no loading is happening', () => { + expect(isListLoading({ listView: createDefaultListView(), active: false })).toBe(false); + }); + + it('returns true when loading is in progress', () => { + const listView = { + currentListResourceState: createListComplexLoadingResourceState( + createDefaultPaginationInfo(), + 200 + ), + currentPaginationInfo: createDefaultPaginationInfo(), + }; + + expect(isListLoading({ listView, active: false })).toBe(true); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/selectors.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/selectors.ts new file mode 100644 index 000000000000..6fde779ac1cc --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/store/selectors.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Immutable, TrustedApp } from '../../../../../common/endpoint/types'; + +import { + AsyncResourceState, + getCurrentResourceError, + getLastLoadedResourceState, + isLoadingResourceState, + isOutdatedResourceState, + LoadedResourceState, + PaginationInfo, + TrustedAppsListData, + TrustedAppsListPageState, +} from '../state'; + +const pageInfosEqual = (pageInfo1: PaginationInfo, pageInfo2: PaginationInfo): boolean => + pageInfo1.index === pageInfo2.index && pageInfo1.size === pageInfo2.size; + +export const needsRefreshOfListData = (state: Immutable): boolean => { + const currentPageInfo = state.listView.currentPaginationInfo; + const currentPage = state.listView.currentListResourceState; + + return ( + state.active && + isOutdatedResourceState(currentPage, (data) => + pageInfosEqual(currentPageInfo, data.paginationInfo) + ) + ); +}; + +export const getCurrentListResourceState = ( + state: Immutable +): Immutable> | undefined => { + return state.listView.currentListResourceState; +}; + +export const getLastLoadedListResourceState = ( + state: Immutable +): Immutable> | undefined => { + return getLastLoadedResourceState(state.listView.currentListResourceState); +}; + +export const getListItems = ( + state: Immutable +): Immutable => { + return getLastLoadedResourceState(state.listView.currentListResourceState)?.data.items || []; +}; + +export const getListCurrentPageIndex = (state: Immutable): number => { + return state.listView.currentPaginationInfo.index; +}; + +export const getListCurrentPageSize = (state: Immutable): number => { + return state.listView.currentPaginationInfo.size; +}; + +export const getListTotalItemsCount = (state: Immutable): number => { + return ( + getLastLoadedResourceState(state.listView.currentListResourceState)?.data.totalItemsCount || 0 + ); +}; + +export const getListErrorMessage = ( + state: Immutable +): string | undefined => { + return getCurrentResourceError(state.listView.currentListResourceState)?.message; +}; + +export const isListLoading = (state: Immutable): boolean => { + return isLoadingResourceState(state.listView.currentListResourceState); +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/test_utils/index.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/test_utils/index.ts new file mode 100644 index 000000000000..fab059a422a2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/test_utils/index.ts @@ -0,0 +1,135 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ServerApiError } from '../../../../common/types'; +import { TrustedApp } from '../../../../../common/endpoint/types'; +import { RoutingAction } from '../../../../common/store/routing'; + +import { + AsyncResourceState, + FailedResourceState, + LoadedResourceState, + LoadingResourceState, + PaginationInfo, + StaleResourceState, + TrustedAppsListData, + TrustedAppsListPageState, + UninitialisedResourceState, +} from '../state'; + +import { TrustedAppsListResourceStateChanged } from '../store/action'; + +const OS_LIST: Array = ['windows', 'macos', 'linux']; + +export const createSampleTrustedApps = (paginationInfo: PaginationInfo): TrustedApp[] => { + return [...new Array(paginationInfo.size).keys()].map((i) => ({ + id: String(paginationInfo.index + i), + name: `trusted app ${paginationInfo.index + i}`, + description: `Trusted App ${paginationInfo.index + i}`, + created_at: '1 minute ago', + created_by: 'someone', + os: OS_LIST[i % 3], + entries: [], + })); +}; + +export const createTrustedAppsListData = ( + paginationInfo: PaginationInfo, + totalItemsCount: number +) => ({ + items: createSampleTrustedApps(paginationInfo), + totalItemsCount, + paginationInfo, +}); + +export const createServerApiError = (message: string) => ({ + statusCode: 500, + error: 'Internal Server Error', + message, +}); + +export const createUninitialisedResourceState = (): UninitialisedResourceState => ({ + type: 'UninitialisedResourceState', +}); + +export const createListLoadedResourceState = ( + paginationInfo: PaginationInfo, + totalItemsCount: number +): LoadedResourceState => ({ + type: 'LoadedResourceState', + data: createTrustedAppsListData(paginationInfo, totalItemsCount), +}); + +export const createListFailedResourceState = ( + message: string, + lastLoadedState?: LoadedResourceState +): FailedResourceState => ({ + type: 'FailedResourceState', + error: createServerApiError(message), + lastLoadedState, +}); + +export const createListLoadingResourceState = ( + previousState: StaleResourceState = createUninitialisedResourceState() +): LoadingResourceState => ({ + type: 'LoadingResourceState', + previousState, +}); + +export const createListComplexLoadingResourceState = ( + paginationInfo: PaginationInfo, + totalItemsCount: number +): LoadingResourceState => + createListLoadingResourceState( + createListFailedResourceState( + 'Internal Server Error', + createListLoadedResourceState(paginationInfo, totalItemsCount) + ) + ); + +export const createDefaultPaginationInfo = () => ({ index: 0, size: 20 }); + +export const createDefaultListView = () => ({ + currentListResourceState: createUninitialisedResourceState(), + currentPaginationInfo: createDefaultPaginationInfo(), +}); + +export const createLoadingListViewWithPagination = ( + currentPaginationInfo: PaginationInfo, + previousState: StaleResourceState = createUninitialisedResourceState() +): TrustedAppsListPageState['listView'] => ({ + currentListResourceState: { type: 'LoadingResourceState', previousState }, + currentPaginationInfo, +}); + +export const createLoadedListViewWithPagination = ( + paginationInfo: PaginationInfo = createDefaultPaginationInfo(), + currentPaginationInfo: PaginationInfo = createDefaultPaginationInfo(), + totalItemsCount: number = 200 +): TrustedAppsListPageState['listView'] => ({ + currentListResourceState: createListLoadedResourceState(paginationInfo, totalItemsCount), + currentPaginationInfo, +}); + +export const createFailedListViewWithPagination = ( + currentPaginationInfo: PaginationInfo, + error: ServerApiError, + lastLoadedState?: LoadedResourceState +): TrustedAppsListPageState['listView'] => ({ + currentListResourceState: { type: 'FailedResourceState', error, lastLoadedState }, + currentPaginationInfo, +}); + +export const createUserChangedUrlAction = (path: string, search: string = ''): RoutingAction => { + return { type: 'userChangedUrl', payload: { pathname: path, search, hash: '' } }; +}; + +export const createTrustedAppsListResourceStateChangedAction = ( + newState: AsyncResourceState +): TrustedAppsListResourceStateChanged => ({ + type: 'trustedAppsListResourceStateChanged', + payload: { newState }, +}); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/__snapshots__/trusted_apps_list.test.tsx.snap b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/__snapshots__/trusted_apps_list.test.tsx.snap new file mode 100644 index 000000000000..e0f846f5950f --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/__snapshots__/trusted_apps_list.test.tsx.snap @@ -0,0 +1,5530 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TrustedAppsList renders correctly initially 1`] = ` +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + OS + +
+
+
+ + Date Created + +
+
+
+ + Created By + +
+
+
+ + No items found + +
+
+
+
+
+`; + +exports[`TrustedAppsList renders correctly when failed loading data for the first time 1`] = ` +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + OS + +
+
+
+ + Date Created + +
+
+
+ + Created By + +
+
+
+ +
+ + Intenal Server Error + +
+
+
+
+
+`; + +exports[`TrustedAppsList renders correctly when failed loading data for the second time 1`] = ` +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + OS + +
+
+
+ + Date Created + +
+
+
+ + Created By + +
+
+
+ +
+ + Intenal Server Error + +
+
+
+
+
+`; + +exports[`TrustedAppsList renders correctly when loaded data 1`] = ` +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + OS + +
+
+
+ + Date Created + +
+
+
+ + Created By + +
+
+
+ Name +
+
+ + trusted app 0 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 1 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 2 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 3 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 4 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 5 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 6 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 7 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 8 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 9 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 10 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 11 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 12 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 13 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 14 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 15 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 16 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 17 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 18 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 19 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+`; + +exports[`TrustedAppsList renders correctly when loading data for the first time 1`] = ` +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + OS + +
+
+
+ + Date Created + +
+
+
+ + Created By + +
+
+
+ + No items found + +
+
+
+
+
+`; + +exports[`TrustedAppsList renders correctly when loading data for the second time 1`] = ` +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + OS + +
+
+
+ + Date Created + +
+
+
+ + Created By + +
+
+
+ Name +
+
+ + trusted app 0 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 1 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 2 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 3 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 4 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 5 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 6 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 7 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 8 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 9 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 10 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 11 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 12 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 13 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 14 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 15 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 16 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 17 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 18 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 19 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+`; + +exports[`TrustedAppsList renders correctly when new page and page sie set (not loading yet) 1`] = ` +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + Name + +
+
+
+ + OS + +
+
+
+ + Date Created + +
+
+
+ + Created By + +
+
+
+ Name +
+
+ + trusted app 0 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 1 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 2 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 3 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 4 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 5 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 6 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 7 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 8 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 9 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 10 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 11 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 12 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 13 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 14 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 15 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 16 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 17 + +
+
+
+ OS +
+
+ Linux +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 18 + +
+
+
+ OS +
+
+ Windows +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+ Name +
+
+ + trusted app 19 + +
+
+
+ OS +
+
+ Mac OS +
+
+
+ Date Created +
+
+ 1 minute ago +
+
+
+ Created By +
+
+ + someone + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+`; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/__snapshots__/trusted_apps_page.test.tsx.snap b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/__snapshots__/trusted_apps_page.test.tsx.snap index 6f074f380903..d6e9aee108cf 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/__snapshots__/trusted_apps_page.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/__snapshots__/trusted_apps_page.test.tsx.snap @@ -17,5 +17,7 @@ exports[`TrustedAppsPage rendering 1`] = ` values={Object {}} /> } -/> +> + + `; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/hooks.ts b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/hooks.ts new file mode 100644 index 000000000000..62610610981e --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/hooks.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useSelector } from 'react-redux'; + +import { State } from '../../../../common/store'; + +import { + MANAGEMENT_STORE_TRUSTED_APPS_NAMESPACE as TRUSTED_APPS_NS, + MANAGEMENT_STORE_GLOBAL_NAMESPACE as GLOBAL_NS, +} from '../../../common/constants'; + +import { TrustedAppsListPageState } from '../state'; + +export function useTrustedAppsSelector(selector: (state: TrustedAppsListPageState) => R): R { + return useSelector((state: State) => + selector(state[GLOBAL_NS][TRUSTED_APPS_NS] as TrustedAppsListPageState) + ); +} diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_list.test.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_list.test.tsx new file mode 100644 index 000000000000..0362f5c7a9de --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_list.test.tsx @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { combineReducers, createStore } from 'redux'; +import { render } from '@testing-library/react'; +import React from 'react'; +import { Provider } from 'react-redux'; + +import { + MANAGEMENT_STORE_GLOBAL_NAMESPACE, + MANAGEMENT_STORE_TRUSTED_APPS_NAMESPACE, +} from '../../../common/constants'; +import { trustedAppsPageReducer } from '../store/reducer'; +import { TrustedAppsList } from './trusted_apps_list'; +import { + createListFailedResourceState, + createListLoadedResourceState, + createListLoadingResourceState, + createTrustedAppsListResourceStateChangedAction, + createUserChangedUrlAction, +} from '../test_utils'; + +jest.mock('@elastic/eui/lib/services/accessibility/html_id_generator', () => ({ + htmlIdGenerator: () => () => 'mockId', +})); + +const createStoreSetup = () => { + return createStore( + combineReducers({ + [MANAGEMENT_STORE_GLOBAL_NAMESPACE]: combineReducers({ + [MANAGEMENT_STORE_TRUSTED_APPS_NAMESPACE]: trustedAppsPageReducer, + }), + }) + ); +}; + +const renderList = (store: ReturnType) => { + const Wrapper: React.FC = ({ children }) => {children}; + + return render(, { wrapper: Wrapper }); +}; + +describe('TrustedAppsList', () => { + it('renders correctly initially', () => { + expect(renderList(createStoreSetup()).container).toMatchSnapshot(); + }); + + it('renders correctly when loading data for the first time', () => { + const store = createStoreSetup(); + + store.dispatch( + createTrustedAppsListResourceStateChangedAction(createListLoadingResourceState()) + ); + + expect(renderList(store).container).toMatchSnapshot(); + }); + + it('renders correctly when failed loading data for the first time', () => { + const store = createStoreSetup(); + + store.dispatch( + createTrustedAppsListResourceStateChangedAction( + createListFailedResourceState('Intenal Server Error') + ) + ); + + expect(renderList(store).container).toMatchSnapshot(); + }); + + it('renders correctly when loaded data', () => { + const store = createStoreSetup(); + + store.dispatch( + createTrustedAppsListResourceStateChangedAction( + createListLoadedResourceState({ index: 0, size: 20 }, 200) + ) + ); + + expect(renderList(store).container).toMatchSnapshot(); + }); + + it('renders correctly when new page and page sie set (not loading yet)', () => { + const store = createStoreSetup(); + + store.dispatch( + createTrustedAppsListResourceStateChangedAction( + createListLoadedResourceState({ index: 0, size: 20 }, 200) + ) + ); + store.dispatch(createUserChangedUrlAction('/trusted_apps', '?page_index=2&page_size=50')); + + expect(renderList(store).container).toMatchSnapshot(); + }); + + it('renders correctly when loading data for the second time', () => { + const store = createStoreSetup(); + + store.dispatch( + createTrustedAppsListResourceStateChangedAction( + createListLoadingResourceState(createListLoadedResourceState({ index: 0, size: 20 }, 200)) + ) + ); + + expect(renderList(store).container).toMatchSnapshot(); + }); + + it('renders correctly when failed loading data for the second time', () => { + const store = createStoreSetup(); + + store.dispatch( + createTrustedAppsListResourceStateChangedAction( + createListFailedResourceState( + 'Intenal Server Error', + createListLoadedResourceState({ index: 0, size: 20 }, 200) + ) + ) + ); + + expect(renderList(store).container).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_list.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_list.tsx new file mode 100644 index 000000000000..a9077dd84913 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_list.tsx @@ -0,0 +1,126 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { memo, useCallback, useMemo } from 'react'; +import { useHistory } from 'react-router-dom'; +import { EuiBasicTable, EuiBasicTableColumn } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { Immutable } from '../../../../../common/endpoint/types'; +import { TrustedApp } from '../../../../../common/endpoint/types/trusted_apps'; +import { MANAGEMENT_PAGE_SIZE_OPTIONS } from '../../../common/constants'; +import { getTrustedAppsListPath } from '../../../common/routing'; + +import { + getListCurrentPageIndex, + getListCurrentPageSize, + getListErrorMessage, + getListItems, + getListTotalItemsCount, + isListLoading, +} from '../store/selectors'; + +import { useTrustedAppsSelector } from './hooks'; + +import { FormattedDate } from '../../../../common/components/formatted_date'; + +const OS_TITLES: Readonly<{ [K in TrustedApp['os']]: string }> = { + windows: i18n.translate('xpack.securitySolution.trustedapps.os.windows', { + defaultMessage: 'Windows', + }), + macos: i18n.translate('xpack.securitySolution.trustedapps.os.macos', { + defaultMessage: 'Mac OS', + }), + linux: i18n.translate('xpack.securitySolution.trustedapps.os.linux', { + defaultMessage: 'Linux', + }), +}; + +const COLUMN_TITLES: Readonly<{ [K in keyof Omit]: string }> = { + name: i18n.translate('xpack.securitySolution.trustedapps.list.columns.name', { + defaultMessage: 'Name', + }), + os: i18n.translate('xpack.securitySolution.trustedapps.list.columns.os', { + defaultMessage: 'OS', + }), + created_at: i18n.translate('xpack.securitySolution.trustedapps.list.columns.createdAt', { + defaultMessage: 'Date Created', + }), + created_by: i18n.translate('xpack.securitySolution.trustedapps.list.columns.createdBy', { + defaultMessage: 'Created By', + }), +}; + +const getColumnDefinitions = (): Array>> => [ + { + field: 'name', + name: COLUMN_TITLES.name, + }, + { + field: 'os', + name: COLUMN_TITLES.os, + render(value: TrustedApp['os'], record: Immutable) { + return OS_TITLES[value]; + }, + }, + { + field: 'created_at', + name: COLUMN_TITLES.created_at, + render(value: TrustedApp['created_at'], record: Immutable) { + return ( + + ); + }, + }, + { + field: 'created_by', + name: COLUMN_TITLES.created_by, + }, +]; + +export const TrustedAppsList = memo(() => { + const pageIndex = useTrustedAppsSelector(getListCurrentPageIndex); + const pageSize = useTrustedAppsSelector(getListCurrentPageSize); + const totalItemCount = useTrustedAppsSelector(getListTotalItemsCount); + const listItems = useTrustedAppsSelector(getListItems); + const history = useHistory(); + + return ( + [...listItems], [listItems])} + error={useTrustedAppsSelector(getListErrorMessage)} + loading={useTrustedAppsSelector(isListLoading)} + pagination={useMemo( + () => ({ + pageIndex, + pageSize, + totalItemCount, + hidePerPageOptions: false, + pageSizeOptions: [...MANAGEMENT_PAGE_SIZE_OPTIONS], + }), + [pageIndex, pageSize, totalItemCount] + )} + onChange={useCallback( + ({ page }: { page: { index: number; size: number } }) => { + history.push( + getTrustedAppsListPath({ + page_index: page.index, + page_size: page.size, + }) + ); + }, + [history] + )} + /> + ); +}); + +TrustedAppsList.displayName = 'TrustedAppsList'; diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.tsx index 7045fa49ffad..c0d3b9cd699d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/trusted_apps_page.tsx @@ -3,11 +3,12 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import React from 'react'; +import React, { memo } from 'react'; import { FormattedMessage } from '@kbn/i18n/react'; import { AdministrationListPage } from '../../../components/administration_list_page'; +import { TrustedAppsList } from './trusted_apps_list'; -export function TrustedAppsPage() { +export const TrustedAppsPage = memo(() => { return ( } - /> + > + + ); -} +}); + +TrustedAppsPage.displayName = 'TrustedAppsPage'; diff --git a/x-pack/plugins/security_solution/public/management/store/middleware.ts b/x-pack/plugins/security_solution/public/management/store/middleware.ts index c7a7d2cad062..77d02262e93b 100644 --- a/x-pack/plugins/security_solution/public/management/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/management/store/middleware.ts @@ -9,22 +9,22 @@ import { SecuritySubPluginMiddlewareFactory, State, } from '../../common/store'; -import { policyListMiddlewareFactory } from '../pages/policy/store/policy_list'; -import { policyDetailsMiddlewareFactory } from '../pages/policy/store/policy_details'; import { MANAGEMENT_STORE_ENDPOINTS_NAMESPACE, MANAGEMENT_STORE_GLOBAL_NAMESPACE, MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE, MANAGEMENT_STORE_POLICY_LIST_NAMESPACE, + MANAGEMENT_STORE_TRUSTED_APPS_NAMESPACE, } from '../common/constants'; +import { policyListMiddlewareFactory } from '../pages/policy/store/policy_list'; +import { policyDetailsMiddlewareFactory } from '../pages/policy/store/policy_details'; import { endpointMiddlewareFactory } from '../pages/endpoint_hosts/store/middleware'; +import { trustedAppsPageMiddlewareFactory } from '../pages/trusted_apps/store/middleware'; + +type ManagementSubStateKey = keyof State[typeof MANAGEMENT_STORE_GLOBAL_NAMESPACE]; -const policyListSelector = (state: State) => - state[MANAGEMENT_STORE_GLOBAL_NAMESPACE][MANAGEMENT_STORE_POLICY_LIST_NAMESPACE]; -const policyDetailsSelector = (state: State) => - state[MANAGEMENT_STORE_GLOBAL_NAMESPACE][MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE]; -const endpointsSelector = (state: State) => - state[MANAGEMENT_STORE_GLOBAL_NAMESPACE][MANAGEMENT_STORE_ENDPOINTS_NAMESPACE]; +const createSubStateSelector = (namespace: K) => (state: State) => + state[MANAGEMENT_STORE_GLOBAL_NAMESPACE][namespace]; export const managementMiddlewareFactory: SecuritySubPluginMiddlewareFactory = ( coreStart, @@ -32,13 +32,20 @@ export const managementMiddlewareFactory: SecuritySubPluginMiddlewareFactory = ( ) => { return [ substateMiddlewareFactory( - policyListSelector, + createSubStateSelector(MANAGEMENT_STORE_POLICY_LIST_NAMESPACE), policyListMiddlewareFactory(coreStart, depsStart) ), substateMiddlewareFactory( - policyDetailsSelector, + createSubStateSelector(MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE), policyDetailsMiddlewareFactory(coreStart, depsStart) ), - substateMiddlewareFactory(endpointsSelector, endpointMiddlewareFactory(coreStart, depsStart)), + substateMiddlewareFactory( + createSubStateSelector(MANAGEMENT_STORE_ENDPOINTS_NAMESPACE), + endpointMiddlewareFactory(coreStart, depsStart) + ), + substateMiddlewareFactory( + createSubStateSelector(MANAGEMENT_STORE_TRUSTED_APPS_NAMESPACE), + trustedAppsPageMiddlewareFactory(coreStart, depsStart) + ), ]; }; diff --git a/x-pack/plugins/security_solution/public/management/store/reducer.ts b/x-pack/plugins/security_solution/public/management/store/reducer.ts index eafd69c875ff..29eb2d289ae1 100644 --- a/x-pack/plugins/security_solution/public/management/store/reducer.ts +++ b/x-pack/plugins/security_solution/public/management/store/reducer.ts @@ -17,6 +17,7 @@ import { MANAGEMENT_STORE_ENDPOINTS_NAMESPACE, MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE, MANAGEMENT_STORE_POLICY_LIST_NAMESPACE, + MANAGEMENT_STORE_TRUSTED_APPS_NAMESPACE, } from '../common/constants'; import { ImmutableCombineReducers } from '../../common/store'; import { Immutable } from '../../../common/endpoint/types'; @@ -25,6 +26,10 @@ import { endpointListReducer, initialEndpointListState, } from '../pages/endpoint_hosts/store/reducer'; +import { + initialTrustedAppsPageState, + trustedAppsPageReducer, +} from '../pages/trusted_apps/store/reducer'; const immutableCombineReducers: ImmutableCombineReducers = combineReducers; @@ -35,6 +40,7 @@ export const mockManagementState: Immutable = { [MANAGEMENT_STORE_POLICY_LIST_NAMESPACE]: initialPolicyListState(), [MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE]: initialPolicyDetailsState(), [MANAGEMENT_STORE_ENDPOINTS_NAMESPACE]: initialEndpointListState, + [MANAGEMENT_STORE_TRUSTED_APPS_NAMESPACE]: initialTrustedAppsPageState, }; /** @@ -44,4 +50,5 @@ export const managementReducer = immutableCombineReducers({ [MANAGEMENT_STORE_POLICY_LIST_NAMESPACE]: policyListReducer, [MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE]: policyDetailsReducer, [MANAGEMENT_STORE_ENDPOINTS_NAMESPACE]: endpointListReducer, + [MANAGEMENT_STORE_TRUSTED_APPS_NAMESPACE]: trustedAppsPageReducer, }); diff --git a/x-pack/plugins/security_solution/public/management/types.ts b/x-pack/plugins/security_solution/public/management/types.ts index 21214241d198..8b53f4c1d852 100644 --- a/x-pack/plugins/security_solution/public/management/types.ts +++ b/x-pack/plugins/security_solution/public/management/types.ts @@ -8,6 +8,7 @@ import { CombinedState } from 'redux'; import { SecurityPageName } from '../app/types'; import { PolicyListState, PolicyDetailsState } from './pages/policy/types'; import { EndpointState } from './pages/endpoint_hosts/types'; +import { TrustedAppsListPageState } from './pages/trusted_apps/state/trusted_apps_list_page_state'; /** * The type for the management store global namespace. Used mostly internally to reference @@ -19,6 +20,7 @@ export type ManagementState = CombinedState<{ policyList: PolicyListState; policyDetails: PolicyDetailsState; endpoints: EndpointState; + trustedApps: TrustedAppsListPageState; }>; /** diff --git a/x-pack/plugins/security_solution/public/network/components/ip_overview/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/network/components/details/__snapshots__/index.test.tsx.snap similarity index 100% rename from x-pack/plugins/security_solution/public/network/components/ip_overview/__snapshots__/index.test.tsx.snap rename to x-pack/plugins/security_solution/public/network/components/details/__snapshots__/index.test.tsx.snap diff --git a/x-pack/plugins/security_solution/public/network/components/ip_overview/index.test.tsx b/x-pack/plugins/security_solution/public/network/components/details/index.test.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/network/components/ip_overview/index.test.tsx rename to x-pack/plugins/security_solution/public/network/components/details/index.test.tsx diff --git a/x-pack/plugins/security_solution/public/network/components/ip_overview/index.tsx b/x-pack/plugins/security_solution/public/network/components/details/index.tsx similarity index 88% rename from x-pack/plugins/security_solution/public/network/components/ip_overview/index.tsx rename to x-pack/plugins/security_solution/public/network/components/details/index.tsx index d6dfe1769308..2c6840895683 100644 --- a/x-pack/plugins/security_solution/public/network/components/ip_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/details/index.tsx @@ -12,7 +12,7 @@ import React from 'react'; import { DEFAULT_DARK_MODE } from '../../../../common/constants'; import { DescriptionList } from '../../../../common/utility_types'; import { useUiSetting$ } from '../../../common/lib/kibana'; -import { FlowTarget, IpOverviewData, Overview } from '../../../graphql/types'; +import { FlowTarget, NetworkDetailsStrategyResponse } from '../../../../common/search_strategy'; import { networkModel } from '../../store'; import { getEmptyTagValue } from '../../../common/components/empty_value'; @@ -34,8 +34,8 @@ import { useMlCapabilities } from '../../../common/components/ml/hooks/use_ml_ca import { hasMlUserPermissions } from '../../../../common/machine_learning/has_ml_user_permissions'; import { InspectButton, InspectButtonContainer } from '../../../common/components/inspect'; -interface OwnProps { - data: IpOverviewData; +export interface IpOverviewProps { + data: NetworkDetailsStrategyResponse['networkDetails']; flowTarget: FlowTarget; id: string; ip: string; @@ -48,15 +48,11 @@ interface OwnProps { narrowDateRange: NarrowDateRange; } -export type IpOverviewProps = OwnProps; - -const getDescriptionList = (descriptionList: DescriptionList[], key: number) => { - return ( - - - - ); -}; +const getDescriptionList = (descriptionList: DescriptionList[], key: number) => ( + + + +); export const IpOverview = React.memo( ({ @@ -74,7 +70,7 @@ export const IpOverview = React.memo( const capabilities = useMlCapabilities(); const userPermissions = hasMlUserPermissions(capabilities); const [darkMode] = useUiSetting$(DEFAULT_DARK_MODE); - const typeData: Overview = data[flowTarget]!; + const typeData = data[flowTarget]!; const column: DescriptionList[] = [ { title: i18n.LOCATION, @@ -124,13 +120,14 @@ export const IpOverview = React.memo( [ { title: i18n.HOST_ID, - description: typeData - ? hostIdRenderer({ host: data.host, ipFilter: ip }) - : getEmptyTagValue(), + description: + typeData && data.host + ? hostIdRenderer({ host: data.host, ipFilter: ip }) + : getEmptyTagValue(), }, { title: i18n.HOST_NAME, - description: typeData ? hostNameRenderer(data.host, ip) : getEmptyTagValue(), + description: typeData && data.host ? hostNameRenderer(data.host, ip) : getEmptyTagValue(), }, ], [ diff --git a/x-pack/plugins/security_solution/public/network/components/ip_overview/mock.ts b/x-pack/plugins/security_solution/public/network/components/details/mock.ts similarity index 85% rename from x-pack/plugins/security_solution/public/network/components/ip_overview/mock.ts rename to x-pack/plugins/security_solution/public/network/components/details/mock.ts index aa86fb177b02..b1187a9b22d9 100644 --- a/x-pack/plugins/security_solution/public/network/components/ip_overview/mock.ts +++ b/x-pack/plugins/security_solution/public/network/components/details/mock.ts @@ -4,9 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IpOverviewData } from '../../../graphql/types'; +import { NetworkDetailsStrategyResponse } from '../../../../common/search_strategy'; -export const mockData: Readonly> = { +export const mockData: Readonly> = { complete: { source: { firstSeen: '2019-02-07T17:19:41.636Z', @@ -16,7 +19,7 @@ export const mockData: Readonly> = { continent_name: ['North America'], city_name: ['New York'], country_iso_code: ['US'], - country_name: null, + country_name: undefined, location: { lat: [40.7214], lon: [-74.0052], @@ -33,7 +36,7 @@ export const mockData: Readonly> = { continent_name: ['North America'], city_name: ['New York'], country_iso_code: ['US'], - country_name: null, + country_name: undefined, location: { lat: [40.7214], lon: [-74.0052], diff --git a/x-pack/plugins/security_solution/public/network/components/ip_overview/translations.ts b/x-pack/plugins/security_solution/public/network/components/details/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/network/components/ip_overview/translations.ts rename to x-pack/plugins/security_solution/public/network/components/details/translations.ts diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/point_tool_tip_content.test.tsx b/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/point_tool_tip_content.test.tsx index 7c05e93e6876..27fe27adc99c 100644 --- a/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/point_tool_tip_content.test.tsx +++ b/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/point_tool_tip_content.test.tsx @@ -11,7 +11,7 @@ import '../../../../common/mock/match_media'; import { getRenderedFieldValue, PointToolTipContentComponent } from './point_tool_tip_content'; import { TestProviders } from '../../../../common/mock'; import { getEmptyStringTag } from '../../../../common/components/empty_value'; -import { HostDetailsLink, IPDetailsLink } from '../../../../common/components/links'; +import { HostDetailsLink, NetworkDetailsLink } from '../../../../common/components/links'; import { FlowTarget } from '../../../../graphql/types'; import { TooltipProperty, @@ -50,17 +50,17 @@ describe('PointToolTipContent', () => { ); }); - test('it returns IPDetailsLink if field is source.ip', () => { + test('it returns NetworkDetailsLink if field is source.ip', () => { const value = '127.0.0.1'; expect(getRenderedFieldValue('source.ip', value)).toStrictEqual( - + ); }); - test('it returns IPDetailsLink if field is destination.ip', () => { + test('it returns NetworkDetailsLink if field is destination.ip', () => { const value = '127.0.0.1'; expect(getRenderedFieldValue('destination.ip', value)).toStrictEqual( - + ); }); diff --git a/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/point_tool_tip_content.tsx b/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/point_tool_tip_content.tsx index f38f3e054a64..57113a139577 100644 --- a/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/point_tool_tip_content.tsx +++ b/x-pack/plugins/security_solution/public/network/components/embeddables/map_tool_tip/point_tool_tip_content.tsx @@ -11,7 +11,7 @@ import { getOrEmptyTagFromValue, } from '../../../../common/components/empty_value'; import { DescriptionListStyled } from '../../../../common/components/page'; -import { HostDetailsLink, IPDetailsLink } from '../../../../common/components/links'; +import { HostDetailsLink, NetworkDetailsLink } from '../../../../common/components/links'; import { DefaultFieldRenderer } from '../../../../timelines/components/field_renderers/field_renderers'; import { FlowTarget } from '../../../../graphql/types'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths @@ -67,7 +67,7 @@ export const getRenderedFieldValue = (field: string, value: string) => { return ; } else if (['source.ip', 'destination.ip'].includes(field)) { const flowTarget = field.split('.')[0] as FlowTarget; - return ; + return ; } return <>{value}; }; diff --git a/x-pack/plugins/security_solution/public/network/components/flow_target_select_connected/index.tsx b/x-pack/plugins/security_solution/public/network/components/flow_target_select_connected/index.tsx index 3ce623cfc97b..6ddcf9119b21 100644 --- a/x-pack/plugins/security_solution/public/network/components/flow_target_select_connected/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/flow_target_select_connected/index.tsx @@ -11,7 +11,7 @@ import { useHistory, useLocation } from 'react-router-dom'; import styled from 'styled-components'; import { FlowDirection, FlowTarget } from '../../../graphql/types'; -import * as i18nIp from '../ip_overview/translations'; +import * as i18nIp from '../details/translations'; import { FlowTargetSelect } from '../flow_controls/flow_target_select'; import { IpOverviewId } from '../../../timelines/components/field_renderers/field_renderers'; @@ -40,7 +40,7 @@ export const FlowTargetSelectConnectedComponent: React.FC = ({ flowTarget const history = useHistory(); const location = useLocation(); - const updateIpDetailsFlowTarget = useCallback( + const updateNetworkDetailsFlowTarget = useCallback( (newFlowTarget: FlowTarget) => { const newPath = getUpdatedFlowTargetPath(location, flowTarget, newFlowTarget); history.push(newPath); @@ -56,7 +56,7 @@ export const FlowTargetSelectConnectedComponent: React.FC = ({ flowTarget selectedDirection={FlowDirection.uniDirectional} selectedTarget={flowTarget} displayTextOverride={[i18nIp.AS_SOURCE, i18nIp.AS_DESTINATION]} - updateFlowTargetAction={updateIpDetailsFlowTarget} + updateFlowTargetAction={updateNetworkDetailsFlowTarget} /> ); diff --git a/x-pack/plugins/security_solution/public/network/components/network_http_table/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/network/components/network_http_table/__snapshots__/index.test.tsx.snap index 875a490d86be..7adee9531b1f 100644 --- a/x-pack/plugins/security_solution/public/network/components/network_http_table/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/network/components/network_http_table/__snapshots__/index.test.tsx.snap @@ -1,102 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`NetworkHttp Table Component rendering it renders the default NetworkHttp table 1`] = ` - -`; +exports[`NetworkHttp Table Component rendering it renders the default NetworkHttp table 1`] = `null`; diff --git a/x-pack/plugins/security_solution/public/network/components/network_http_table/columns.tsx b/x-pack/plugins/security_solution/public/network/components/network_http_table/columns.tsx index 0c5856241c5a..42e52e3a86f4 100644 --- a/x-pack/plugins/security_solution/public/network/components/network_http_table/columns.tsx +++ b/x-pack/plugins/security_solution/public/network/components/network_http_table/columns.tsx @@ -8,10 +8,14 @@ import React from 'react'; import numeral from '@elastic/numeral'; -import { NetworkHttpEdges, NetworkHttpFields, NetworkHttpItem } from '../../../graphql/types'; +import { + NetworkHttpEdges, + NetworkHttpFields, + NetworkHttpItem, +} from '../../../../common/search_strategy/security_solution/network'; import { escapeDataProviderId } from '../../../common/components/drag_and_drop/helpers'; import { getEmptyTagValue } from '../../../common/components/empty_value'; -import { IPDetailsLink } from '../../../common/components/links'; +import { NetworkDetailsLink } from '../../../common/components/links'; import { Columns } from '../../../common/components/paginated_table'; import * as i18n from './translations'; @@ -98,7 +102,7 @@ export const getNetworkHttpColumns = (tableId: string): NetworkHttpColumns => [ attrName: 'source.ip', idPrefix: escapeDataProviderId(`${tableId}-table-lastSourceIp-${path}`), rowItem: lastSourceIp, - render: () => , + render: () => , }) : getEmptyTagValue(), }, diff --git a/x-pack/plugins/security_solution/public/network/components/network_http_table/index.tsx b/x-pack/plugins/security_solution/public/network/components/network_http_table/index.tsx index ed2537301820..ccb238bcee27 100644 --- a/x-pack/plugins/security_solution/public/network/components/network_http_table/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/network_http_table/index.tsx @@ -5,17 +5,17 @@ */ import React, { useCallback, useMemo } from 'react'; -import { connect, ConnectedProps } from 'react-redux'; +import { useDispatch, useSelector, shallowEqual } from 'react-redux'; import { networkActions, networkModel, networkSelectors } from '../../store'; -import { Direction, NetworkHttpEdges, NetworkHttpFields } from '../../../graphql/types'; +import { NetworkHttpEdges, NetworkHttpFields } from '../../../../common/search_strategy'; import { State } from '../../../common/store'; import { Criteria, ItemsPerRow, PaginatedTable } from '../../../common/components/paginated_table'; import { getNetworkHttpColumns } from './columns'; import * as i18n from './translations'; -interface OwnProps { +interface NetworkHttpTableProps { data: NetworkHttpEdges[]; fakeTotalCount: number; id: string; @@ -27,8 +27,6 @@ interface OwnProps { type: networkModel.NetworkType; } -type NetworkHttpTableProps = OwnProps & PropsFromRedux; - const rowItems: ItemsPerRow[] = [ { text: i18n.ROWS_5, @@ -41,60 +39,68 @@ const rowItems: ItemsPerRow[] = [ ]; const NetworkHttpTableComponent: React.FC = ({ - activePage, data, fakeTotalCount, id, isInspect, - limit, loading, loadPage, showMorePagesIndicator, - sort, totalCount, type, - updateNetworkTable, }) => { + const dispatch = useDispatch(); + const getNetworkHttpSelector = networkSelectors.httpSelector(); + const { activePage, limit, sort } = useSelector( + (state: State) => getNetworkHttpSelector(state, type), + shallowEqual + ); const tableType = type === networkModel.NetworkType.page ? networkModel.NetworkTableType.http - : networkModel.IpDetailsTableType.http; + : networkModel.NetworkDetailsTableType.http; const updateLimitPagination = useCallback( (newLimit) => - updateNetworkTable({ - networkType: type, - tableType, - updates: { limit: newLimit }, - }), - [type, updateNetworkTable, tableType] + dispatch( + networkActions.updateNetworkTable({ + networkType: type, + tableType, + updates: { limit: newLimit }, + }) + ), + [dispatch, type, tableType] ); const updateActivePage = useCallback( (newPage) => - updateNetworkTable({ - networkType: type, - tableType, - updates: { activePage: newPage }, - }), - [type, updateNetworkTable, tableType] + dispatch( + networkActions.updateNetworkTable({ + networkType: type, + tableType, + updates: { activePage: newPage }, + }) + ), + [dispatch, type, tableType] ); const onChange = useCallback( (criteria: Criteria) => { if (criteria.sort != null && criteria.sort.direction !== sort.direction) { - updateNetworkTable({ - networkType: type, - tableType, - updates: { - sort: { - direction: criteria.sort.direction as Direction, + dispatch( + networkActions.updateNetworkTable({ + networkType: type, + tableType, + updates: { + sort: { + direction: criteria.sort.direction, + }, }, - }, - }); + }) + ); } }, - [tableType, sort.direction, type, updateNetworkTable] + [sort.direction, dispatch, type, tableType] ); const sorting = { field: `node.${NetworkHttpFields.requestCount}`, direction: sort.direction }; @@ -128,18 +134,4 @@ const NetworkHttpTableComponent: React.FC = ({ NetworkHttpTableComponent.displayName = 'NetworkHttpTableComponent'; -const makeMapStateToProps = () => { - const getNetworkHttpSelector = networkSelectors.httpSelector(); - const mapStateToProps = (state: State, { type }: OwnProps) => getNetworkHttpSelector(state, type); - return mapStateToProps; -}; - -const mapDispatchToProps = { - updateNetworkTable: networkActions.updateNetworkTable, -}; - -const connector = connect(makeMapStateToProps, mapDispatchToProps); - -type PropsFromRedux = ConnectedProps; - -export const NetworkHttpTable = connector(React.memo(NetworkHttpTableComponent)); +export const NetworkHttpTable = React.memo(NetworkHttpTableComponent); diff --git a/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/columns.tsx b/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/columns.tsx index d6661ed48197..634bf2ba35d7 100644 --- a/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/columns.tsx +++ b/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/columns.tsx @@ -37,7 +37,7 @@ export type NetworkTopCountriesColumns = [ Columns ]; -export type NetworkTopCountriesColumnsIpDetails = [ +export type NetworkTopCountriesColumnsNetworkDetails = [ Columns, Columns, Columns, @@ -164,7 +164,7 @@ export const getCountriesColumnsCurated = ( flowTarget: FlowTargetSourceDest, type: networkModel.NetworkType, tableId: string -): NetworkTopCountriesColumns | NetworkTopCountriesColumnsIpDetails => { +): NetworkTopCountriesColumns | NetworkTopCountriesColumnsNetworkDetails => { const columns = getNetworkTopCountriesColumns(indexPattern, flowTarget, type, tableId); // Columns to exclude from host details pages diff --git a/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx b/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx index 114bca9f59d9..2495f9e7c11c 100644 --- a/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/network_top_countries_table/index.tsx @@ -88,8 +88,8 @@ const NetworkTopCountriesTableComponent: React.FC } return flowTargeted === FlowTargetSourceDest.source - ? networkModel.IpDetailsTableType.topCountriesSource - : networkModel.IpDetailsTableType.topCountriesDestination; + ? networkModel.NetworkDetailsTableType.topCountriesSource + : networkModel.NetworkDetailsTableType.topCountriesDestination; }, [flowTargeted, type]); const field = diff --git a/x-pack/plugins/security_solution/public/network/components/network_top_n_flow_table/columns.tsx b/x-pack/plugins/security_solution/public/network/components/network_top_n_flow_table/columns.tsx index 16c26d5077c8..ae390e8e2ed7 100644 --- a/x-pack/plugins/security_solution/public/network/components/network_top_n_flow_table/columns.tsx +++ b/x-pack/plugins/security_solution/public/network/components/network_top_n_flow_table/columns.tsx @@ -22,7 +22,7 @@ import { } from '../../../common/components/drag_and_drop/draggable_wrapper'; import { escapeDataProviderId } from '../../../common/components/drag_and_drop/helpers'; import { getEmptyTagValue } from '../../../common/components/empty_value'; -import { IPDetailsLink } from '../../../common/components/links'; +import { NetworkDetailsLink } from '../../../common/components/links'; import { Columns } from '../../../common/components/paginated_table'; import { IS_OPERATOR } from '../../../timelines/components/timeline/data_providers/data_provider'; import { Provider } from '../../../timelines/components/timeline/data_providers/provider'; @@ -43,7 +43,7 @@ export type NetworkTopNFlowColumns = [ Columns ]; -export type NetworkTopNFlowColumnsIpDetails = [ +export type NetworkTopNFlowColumnsNetworkDetails = [ Columns, Columns, Columns, @@ -86,7 +86,7 @@ export const getNetworkTopNFlowColumns = ( ) : ( - + ) } /> @@ -239,7 +239,7 @@ export const getNFlowColumnsCurated = ( flowTarget: FlowTargetSourceDest, type: networkModel.NetworkType, tableId: string -): NetworkTopNFlowColumns | NetworkTopNFlowColumnsIpDetails => { +): NetworkTopNFlowColumns | NetworkTopNFlowColumnsNetworkDetails => { const columns = getNetworkTopNFlowColumns(flowTarget, tableId); // Columns to exclude from host details pages diff --git a/x-pack/plugins/security_solution/public/network/components/network_top_n_flow_table/index.tsx b/x-pack/plugins/security_solution/public/network/components/network_top_n_flow_table/index.tsx index 30b70872432f..757b178431d9 100644 --- a/x-pack/plugins/security_solution/public/network/components/network_top_n_flow_table/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/network_top_n_flow_table/index.tsx @@ -82,8 +82,8 @@ const NetworkTopNFlowTableComponent: React.FC = ({ } else { tableType = flowTargeted === FlowTargetSourceDest.source - ? networkModel.IpDetailsTableType.topNFlowSource - : networkModel.IpDetailsTableType.topNFlowDestination; + ? networkModel.NetworkDetailsTableType.topNFlowSource + : networkModel.NetworkDetailsTableType.topNFlowDestination; } const onChange = useCallback( diff --git a/x-pack/plugins/security_solution/public/network/components/tls_table/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/network/components/tls_table/__snapshots__/index.test.tsx.snap index 8b7d8efa7ac3..a9c3a1a00626 100644 --- a/x-pack/plugins/security_solution/public/network/components/tls_table/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/network/components/tls_table/__snapshots__/index.test.tsx.snap @@ -1,79 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Tls Table Component Rendering it renders the default Domains table 1`] = ` - -`; +exports[`Tls Table Component Rendering it renders the default Domains table 1`] = `null`; diff --git a/x-pack/plugins/security_solution/public/network/components/tls_table/index.tsx b/x-pack/plugins/security_solution/public/network/components/tls_table/index.tsx index d0e001466518..3d19eedc06a8 100644 --- a/x-pack/plugins/security_solution/public/network/components/tls_table/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/tls_table/index.tsx @@ -5,11 +5,16 @@ */ import React, { useCallback, useMemo } from 'react'; -import { connect, ConnectedProps } from 'react-redux'; +import { useDispatch, useSelector, shallowEqual } from 'react-redux'; import deepEqual from 'fast-deep-equal'; import { networkActions, networkModel, networkSelectors } from '../../store'; -import { TlsEdges, TlsSortField, TlsFields, Direction } from '../../../graphql/types'; +import { + Direction, + NetworkTlsEdges, + NetworkTlsFields, + SortField, +} from '../../../../common/search_strategy'; import { State } from '../../../common/store'; import { Criteria, @@ -20,8 +25,8 @@ import { import { getTlsColumns } from './columns'; import * as i18n from './translations'; -interface OwnProps { - data: TlsEdges[]; +interface TlsTableProps { + data: NetworkTlsEdges[]; fakeTotalCount: number; id: string; isInspect: boolean; @@ -32,8 +37,6 @@ interface OwnProps { type: networkModel.NetworkType; } -type TlsTableProps = OwnProps & PropsFromRedux; - const rowItems: ItemsPerRow[] = [ { text: i18n.ROWS_5, @@ -47,123 +50,115 @@ const rowItems: ItemsPerRow[] = [ export const tlsTableId = 'tls-table'; -const TlsTableComponent = React.memo( - ({ - activePage, - data, - fakeTotalCount, - id, - isInspect, - limit, - loading, - loadPage, - showMorePagesIndicator, - sort, - totalCount, - type, - updateNetworkTable, - }) => { - const tableType: networkModel.TopTlsTableType = - type === networkModel.NetworkType.page - ? networkModel.NetworkTableType.tls - : networkModel.IpDetailsTableType.tls; - - const updateLimitPagination = useCallback( - (newLimit) => - updateNetworkTable({ +const TlsTableComponent: React.FC = ({ + data, + fakeTotalCount, + id, + isInspect, + loading, + loadPage, + showMorePagesIndicator, + totalCount, + type, +}) => { + const dispatch = useDispatch(); + const getTlsSelector = networkSelectors.tlsSelector(); + const { activePage, limit, sort } = useSelector( + (state: State) => getTlsSelector(state, type), + shallowEqual + ); + const tableType: networkModel.TopTlsTableType = + type === networkModel.NetworkType.page + ? networkModel.NetworkTableType.tls + : networkModel.NetworkDetailsTableType.tls; + + const updateLimitPagination = useCallback( + (newLimit) => + dispatch( + networkActions.updateNetworkTable({ networkType: type, tableType, updates: { limit: newLimit }, - }), - [type, updateNetworkTable, tableType] - ); - - const updateActivePage = useCallback( - (newPage) => - updateNetworkTable({ + }) + ), + [dispatch, type, tableType] + ); + + const updateActivePage = useCallback( + (newPage) => + dispatch( + networkActions.updateNetworkTable({ networkType: type, tableType, updates: { activePage: newPage }, - }), - [type, updateNetworkTable, tableType] - ); - - const onChange = useCallback( - (criteria: Criteria) => { - if (criteria.sort != null) { - const splitField = criteria.sort.field.split('.'); - const newTlsSort: TlsSortField = { - field: getSortFromString(splitField[splitField.length - 1]), - direction: criteria.sort.direction as Direction, - }; - if (!deepEqual(newTlsSort, sort)) { - updateNetworkTable({ + }) + ), + [dispatch, type, tableType] + ); + + const onChange = useCallback( + (criteria: Criteria) => { + if (criteria.sort != null) { + const splitField = criteria.sort.field.split('.'); + const newTlsSort: SortField = { + field: getSortFromString(splitField[splitField.length - 1]), + direction: criteria.sort.direction as Direction, + }; + if (!deepEqual(newTlsSort, sort)) { + dispatch( + networkActions.updateNetworkTable({ networkType: type, tableType, updates: { sort: newTlsSort }, - }); - } + }) + ); } - }, - [sort, type, tableType, updateNetworkTable] - ); - - // eslint-disable-next-line react-hooks/exhaustive-deps - const columns = useMemo(() => getTlsColumns(tlsTableId), [tlsTableId]); - - return ( - - ); - } -); - -TlsTableComponent.displayName = 'TlsTableComponent'; - -const makeMapStateToProps = () => { - const getTlsSelector = networkSelectors.tlsSelector(); - return (state: State, { type }: OwnProps) => getTlsSelector(state, type); + } + }, + [sort, dispatch, type, tableType] + ); + + const columns = useMemo(() => getTlsColumns(tlsTableId), []); + + return ( + + ); }; -const mapDispatchToProps = { - updateNetworkTable: networkActions.updateNetworkTable, -}; - -const connector = connect(makeMapStateToProps, mapDispatchToProps); - -type PropsFromRedux = ConnectedProps; +TlsTableComponent.displayName = 'TlsTableComponent'; -export const TlsTable = connector(TlsTableComponent); +export const TlsTable = React.memo(TlsTableComponent); -const getSortField = (sortField: TlsSortField): SortingBasicTable => ({ +const getSortField = (sortField: SortField): SortingBasicTable => ({ field: `node.${sortField.field}`, direction: sortField.direction, }); -const getSortFromString = (sortField: string): TlsFields => { +const getSortFromString = (sortField: string): NetworkTlsFields => { switch (sortField) { case '_id': - return TlsFields._id; + return NetworkTlsFields._id; default: - return TlsFields._id; + return NetworkTlsFields._id; } }; diff --git a/x-pack/plugins/security_solution/public/network/components/users_table/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/network/components/users_table/__snapshots__/index.test.tsx.snap index 634253d03291..934a28fbc4dd 100644 --- a/x-pack/plugins/security_solution/public/network/components/users_table/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/network/components/users_table/__snapshots__/index.test.tsx.snap @@ -1,83 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Users Table Component Rendering it renders the default Users table 1`] = ` - -`; +exports[`Users Table Component Rendering it renders the default Users table 1`] = `null`; diff --git a/x-pack/plugins/security_solution/public/network/components/users_table/index.tsx b/x-pack/plugins/security_solution/public/network/components/users_table/index.tsx index 9a971e0087d1..0355d0a30cfa 100644 --- a/x-pack/plugins/security_solution/public/network/components/users_table/index.tsx +++ b/x-pack/plugins/security_solution/public/network/components/users_table/index.tsx @@ -5,7 +5,7 @@ */ import React, { useCallback, useMemo } from 'react'; -import { connect, ConnectedProps } from 'react-redux'; +import { useDispatch, useSelector, shallowEqual } from 'react-redux'; import deepEqual from 'fast-deep-equal'; import { assertUnreachable } from '../../../../common/utility_types'; @@ -13,11 +13,10 @@ import { networkActions, networkModel, networkSelectors } from '../../store'; import { Direction, FlowTarget, - UsersEdges, - UsersFields, - UsersSortField, -} from '../../../graphql/types'; -import { State } from '../../../common/store'; + NetworkUsersEdges, + NetworkUsersFields, + SortField, +} from '../../../../common/search_strategy'; import { Criteria, ItemsPerRow, @@ -27,10 +26,10 @@ import { import { getUsersColumns } from './columns'; import * as i18n from './translations'; -const tableType = networkModel.IpDetailsTableType.users; +const tableType = networkModel.NetworkDetailsTableType.users; -interface OwnProps { - data: UsersEdges[]; +interface UsersTableProps { + data: NetworkUsersEdges[]; flowTarget: FlowTarget; fakeTotalCount: number; id: string; @@ -42,8 +41,6 @@ interface OwnProps { type: networkModel.NetworkType; } -type UsersTableProps = OwnProps & PropsFromRedux; - const rowItems: ItemsPerRow[] = [ { text: i18n.ROWS_5, @@ -57,122 +54,110 @@ const rowItems: ItemsPerRow[] = [ export const usersTableId = 'users-table'; -const UsersTableComponent = React.memo( - ({ - activePage, - data, - fakeTotalCount, - flowTarget, - id, - isInspect, - limit, - loading, - loadPage, - showMorePagesIndicator, - totalCount, - type, - updateNetworkTable, - sort, - }) => { - const updateLimitPagination = useCallback( - (newLimit) => - updateNetworkTable({ +const UsersTableComponent: React.FC = ({ + data, + fakeTotalCount, + flowTarget, + id, + isInspect, + loading, + loadPage, + showMorePagesIndicator, + totalCount, + type, +}) => { + const dispatch = useDispatch(); + const getUsersSelector = networkSelectors.usersSelector(); + const { activePage, sort, limit } = useSelector(getUsersSelector, shallowEqual); + const updateLimitPagination = useCallback( + (newLimit) => + dispatch( + networkActions.updateNetworkTable({ networkType: type, tableType, updates: { limit: newLimit }, - }), - [type, updateNetworkTable] - ); - - const updateActivePage = useCallback( - (newPage) => - updateNetworkTable({ + }) + ), + [dispatch, type] + ); + + const updateActivePage = useCallback( + (newPage) => + dispatch( + networkActions.updateNetworkTable({ networkType: type, tableType, updates: { activePage: newPage }, - }), - [type, updateNetworkTable] - ); - - const onChange = useCallback( - (criteria: Criteria) => { - if (criteria.sort != null) { - const splitField = criteria.sort.field.split('.'); - const newUsersSort: UsersSortField = { - field: getSortFromString(splitField[splitField.length - 1]), - direction: criteria.sort.direction as Direction, - }; - if (!deepEqual(newUsersSort, sort)) { - updateNetworkTable({ + }) + ), + [dispatch, type] + ); + + const onChange = useCallback( + (criteria: Criteria) => { + if (criteria.sort != null) { + const splitField = criteria.sort.field.split('.'); + const newUsersSort: SortField = { + field: getSortFromString(splitField[splitField.length - 1]), + direction: criteria.sort.direction as Direction, + }; + if (!deepEqual(newUsersSort, sort)) { + dispatch( + networkActions.updateNetworkTable({ networkType: type, tableType, updates: { sort: newUsersSort }, - }); - } + }) + ); } - }, - [sort, type, updateNetworkTable] - ); - - // eslint-disable-next-line react-hooks/exhaustive-deps - const columns = useMemo(() => getUsersColumns(flowTarget, usersTableId), [ - flowTarget, - usersTableId, - ]); - - return ( - - ); - } -); + } + }, + [dispatch, sort, type] + ); -UsersTableComponent.displayName = 'UsersTableComponent'; - -const makeMapStateToProps = () => { - const getUsersSelector = networkSelectors.usersSelector(); - return (state: State) => ({ - ...getUsersSelector(state), - }); -}; - -const mapDispatchToProps = { - updateNetworkTable: networkActions.updateNetworkTable, + // eslint-disable-next-line react-hooks/exhaustive-deps + const columns = useMemo(() => getUsersColumns(flowTarget, usersTableId), [ + flowTarget, + usersTableId, + ]); + + return ( + + ); }; -const connector = connect(makeMapStateToProps, mapDispatchToProps); - -type PropsFromRedux = ConnectedProps; +UsersTableComponent.displayName = 'UsersTableComponent'; -export const UsersTable = connector(UsersTableComponent); +export const UsersTable = React.memo(UsersTableComponent); -const getSortField = (sortField: UsersSortField): SortingBasicTable => { +const getSortField = (sortField: SortField): SortingBasicTable => { switch (sortField.field) { - case UsersFields.name: + case NetworkUsersFields.name: return { field: `node.user.${sortField.field}`, direction: sortField.direction, }; - case UsersFields.count: + case NetworkUsersFields.count: return { field: `node.user.${sortField.field}`, direction: sortField.direction, @@ -181,13 +166,13 @@ const getSortField = (sortField: UsersSortField): SortingBasicTable => { return assertUnreachable(sortField.field); }; -const getSortFromString = (sortField: string): UsersFields => { +const getSortFromString = (sortField: string): NetworkUsersFields => { switch (sortField) { - case UsersFields.name.valueOf(): - return UsersFields.name; - case UsersFields.count.valueOf(): - return UsersFields.count; + case NetworkUsersFields.name.valueOf(): + return NetworkUsersFields.name; + case NetworkUsersFields.count.valueOf(): + return NetworkUsersFields.count; default: - return UsersFields.name; + return NetworkUsersFields.name; } }; diff --git a/x-pack/plugins/security_solution/public/network/containers/ip_overview/index.gql_query.ts b/x-pack/plugins/security_solution/public/network/containers/details/index.gql_query.ts similarity index 100% rename from x-pack/plugins/security_solution/public/network/containers/ip_overview/index.gql_query.ts rename to x-pack/plugins/security_solution/public/network/containers/details/index.gql_query.ts diff --git a/x-pack/plugins/security_solution/public/network/containers/details/index.tsx b/x-pack/plugins/security_solution/public/network/containers/details/index.tsx new file mode 100644 index 000000000000..597f85ff082e --- /dev/null +++ b/x-pack/plugins/security_solution/public/network/containers/details/index.tsx @@ -0,0 +1,153 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { noop } from 'lodash/fp'; +import { useState, useEffect, useCallback, useRef } from 'react'; +import deepEqual from 'fast-deep-equal'; + +import { ESTermQuery } from '../../../../common/typed_json'; +import { DEFAULT_INDEX_KEY } from '../../../../common/constants'; +import { inputsModel } from '../../../common/store'; +import { useKibana } from '../../../common/lib/kibana'; +import { createFilter } from '../../../common/containers/helpers'; +import { + DocValueFields, + NetworkQueries, + NetworkDetailsRequestOptions, + NetworkDetailsStrategyResponse, +} from '../../../../common/search_strategy'; +import { AbortError } from '../../../../../../../src/plugins/data/common'; +import * as i18n from './translations'; +import { getInspectResponse } from '../../../helpers'; +import { InspectResponse } from '../../../types'; + +const ID = 'networkDetailsQuery'; + +export interface NetworkDetailsArgs { + id: string; + inspect: InspectResponse; + networkDetails: NetworkDetailsStrategyResponse['networkDetails']; + refetch: inputsModel.Refetch; + isInspected: boolean; +} + +interface UseNetworkDetails { + id?: string; + docValueFields: DocValueFields[]; + ip: string; + filterQuery?: ESTermQuery | string; + skip: boolean; +} + +export const useNetworkDetails = ({ + docValueFields, + filterQuery, + id = ID, + skip, + ip, +}: UseNetworkDetails): [boolean, NetworkDetailsArgs] => { + const { data, notifications, uiSettings } = useKibana().services; + const refetch = useRef(noop); + const abortCtrl = useRef(new AbortController()); + const defaultIndex = uiSettings.get(DEFAULT_INDEX_KEY); + const [loading, setLoading] = useState(false); + + const [networkDetailsRequest, setNetworkDetailsRequest] = useState({ + defaultIndex, + docValueFields: docValueFields ?? [], + factoryQueryType: NetworkQueries.details, + filterQuery: createFilter(filterQuery), + ip, + }); + + const [networkDetailsResponse, setNetworkDetailsResponse] = useState({ + networkDetails: {}, + id, + inspect: { + dsl: [], + response: [], + }, + isInspected: false, + refetch: refetch.current, + }); + + const networkDetailsSearch = useCallback( + (request: NetworkDetailsRequestOptions) => { + let didCancel = false; + const asyncSearch = async () => { + abortCtrl.current = new AbortController(); + setLoading(true); + + const searchSubscription$ = data.search + .search(request, { + strategy: 'securitySolutionSearchStrategy', + abortSignal: abortCtrl.current.signal, + }) + .subscribe({ + next: (response) => { + if (!response.isPartial && !response.isRunning) { + if (!didCancel) { + setLoading(false); + setNetworkDetailsResponse((prevResponse) => ({ + ...prevResponse, + networkDetails: response.networkDetails, + inspect: getInspectResponse(response, prevResponse.inspect), + refetch: refetch.current, + })); + } + searchSubscription$.unsubscribe(); + } else if (response.isPartial && !response.isRunning) { + if (!didCancel) { + setLoading(false); + } + // TODO: Make response error status clearer + notifications.toasts.addWarning(i18n.ERROR_NETWORK_DETAILS); + searchSubscription$.unsubscribe(); + } + }, + error: (msg) => { + if (!(msg instanceof AbortError)) { + notifications.toasts.addDanger({ + title: i18n.FAIL_NETWORK_DETAILS, + text: msg.message, + }); + } + }, + }); + }; + abortCtrl.current.abort(); + asyncSearch(); + refetch.current = asyncSearch; + return () => { + didCancel = true; + abortCtrl.current.abort(); + }; + }, + [data.search, notifications.toasts] + ); + + useEffect(() => { + setNetworkDetailsRequest((prevRequest) => { + const myRequest = { + ...prevRequest, + defaultIndex, + ip, + docValueFields: docValueFields ?? [], + filterQuery: createFilter(filterQuery), + }; + if (!skip && !deepEqual(prevRequest, myRequest)) { + return myRequest; + } + return prevRequest; + }); + }, [defaultIndex, filterQuery, skip, ip, docValueFields]); + + useEffect(() => { + networkDetailsSearch(networkDetailsRequest); + }, [networkDetailsRequest, networkDetailsSearch]); + + return [loading, networkDetailsResponse]; +}; diff --git a/x-pack/plugins/security_solution/public/network/containers/details/translations.ts b/x-pack/plugins/security_solution/public/network/containers/details/translations.ts new file mode 100644 index 000000000000..4aedd685630b --- /dev/null +++ b/x-pack/plugins/security_solution/public/network/containers/details/translations.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const ERROR_NETWORK_DETAILS = i18n.translate( + 'xpack.securitySolution.networkDetails.errorSearchDescription', + { + defaultMessage: `An error has occurred on network details search`, + } +); + +export const FAIL_NETWORK_DETAILS = i18n.translate( + 'xpack.securitySolution.networkDetails.failSearchDescription', + { + defaultMessage: `Failed to run search on network details`, + } +); diff --git a/x-pack/plugins/security_solution/public/network/containers/ip_overview/index.tsx b/x-pack/plugins/security_solution/public/network/containers/ip_overview/index.tsx deleted file mode 100644 index 6c8b54cc7951..000000000000 --- a/x-pack/plugins/security_solution/public/network/containers/ip_overview/index.tsx +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { getOr } from 'lodash/fp'; -import React from 'react'; -import { Query } from 'react-apollo'; -import { connect, ConnectedProps } from 'react-redux'; - -import { DEFAULT_INDEX_KEY } from '../../../../common/constants'; -import { GetIpOverviewQuery, IpOverviewData } from '../../../graphql/types'; -import { inputsModel, inputsSelectors, State } from '../../../common/store'; -import { useUiSetting } from '../../../common/lib/kibana'; -import { createFilter, getDefaultFetchPolicy } from '../../../common/containers/helpers'; -import { QueryTemplateProps } from '../../../common/containers/query_template'; -import { networkModel } from '../../store'; -import { ipOverviewQuery } from './index.gql_query'; - -const ID = 'ipOverviewQuery'; - -export interface IpOverviewArgs { - id: string; - inspect: inputsModel.InspectQuery; - ipOverviewData: IpOverviewData; - loading: boolean; - refetch: inputsModel.Refetch; -} - -export interface IpOverviewProps extends QueryTemplateProps { - children: (args: IpOverviewArgs) => React.ReactNode; - type: networkModel.NetworkType; - ip: string; -} - -const IpOverviewComponentQuery = React.memo( - ({ id = ID, docValueFields, isInspected, children, filterQuery, skip, sourceId, ip }) => ( - - query={ipOverviewQuery} - fetchPolicy={getDefaultFetchPolicy()} - notifyOnNetworkStatusChange - skip={skip} - variables={{ - sourceId, - filterQuery: createFilter(filterQuery), - ip, - defaultIndex: useUiSetting(DEFAULT_INDEX_KEY), - docValueFields: docValueFields ?? [], - inspect: isInspected, - }} - > - {({ data, loading, refetch }) => { - const init: IpOverviewData = { host: {} }; - const ipOverviewData: IpOverviewData = getOr(init, 'source.IpOverview', data); - return children({ - id, - inspect: getOr(null, 'source.IpOverview.inspect', data), - ipOverviewData, - loading, - refetch, - }); - }} - - ) -); - -IpOverviewComponentQuery.displayName = 'IpOverviewComponentQuery'; - -const makeMapStateToProps = () => { - const getQuery = inputsSelectors.globalQueryByIdSelector(); - const mapStateToProps = (state: State, { id = ID }: IpOverviewProps) => { - const { isInspected } = getQuery(state, id); - return { - isInspected, - }; - }; - return mapStateToProps; -}; - -const connector = connect(makeMapStateToProps); - -type PropsFromRedux = ConnectedProps; - -export const IpOverviewQuery = connector(IpOverviewComponentQuery); diff --git a/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx b/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx index 53d9a303ab84..6f48cba2ebda 100644 --- a/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/network_dns/index.tsx @@ -175,10 +175,6 @@ export const useNetworkDns = ({ ); useEffect(() => { - if (skip) { - return; - } - setNetworkDnsRequest((prevRequest) => { const myRequest = { ...prevRequest, @@ -193,7 +189,7 @@ export const useNetworkDns = ({ to: endDate, }, }; - if (!deepEqual(prevRequest, myRequest)) { + if (!skip && !deepEqual(prevRequest, myRequest)) { return myRequest; } return prevRequest; diff --git a/x-pack/plugins/security_solution/public/network/containers/users/index.tsx b/x-pack/plugins/security_solution/public/network/containers/users/index.tsx index efbeb3eb0054..608ccdb08470 100644 --- a/x-pack/plugins/security_solution/public/network/containers/users/index.tsx +++ b/x-pack/plugins/security_solution/public/network/containers/users/index.tsx @@ -4,154 +4,195 @@ * you may not use this file except in compliance with the Elastic License. */ -import { getOr } from 'lodash/fp'; -import React from 'react'; -import { Query } from 'react-apollo'; -import { connect, ConnectedProps } from 'react-redux'; -import { compose } from 'redux'; +import { noop } from 'lodash/fp'; +import { useState, useEffect, useCallback, useRef } from 'react'; +import { shallowEqual, useSelector } from 'react-redux'; +import deepEqual from 'fast-deep-equal'; +import { ESTermQuery } from '../../../../common/typed_json'; import { DEFAULT_INDEX_KEY } from '../../../../common/constants'; -import { GetUsersQuery, FlowTarget, PageInfoPaginated, UsersEdges } from '../../../graphql/types'; -import { inputsModel, State, inputsSelectors } from '../../../common/store'; -import { withKibana, WithKibanaProps } from '../../../common/lib/kibana'; -import { createFilter, getDefaultFetchPolicy } from '../../../common/containers/helpers'; +import { inputsModel } from '../../../common/store'; +import { useKibana } from '../../../common/lib/kibana'; +import { createFilter } from '../../../common/containers/helpers'; +import { PageInfoPaginated } from '../../../graphql/types'; import { generateTablePaginationOptions } from '../../../common/components/paginated_table/helpers'; +import { networkSelectors } from '../../store'; import { - QueryTemplatePaginated, - QueryTemplatePaginatedProps, -} from '../../../common/containers/query_template_paginated'; -import { networkModel, networkSelectors } from '../../store'; + FlowTarget, + NetworkQueries, + NetworkUsersRequestOptions, + NetworkUsersStrategyResponse, +} from '../../../../common/search_strategy/security_solution/network'; +import { AbortError } from '../../../../../../../src/plugins/data/common'; +import * as i18n from './translations'; +import { getInspectResponse } from '../../../helpers'; +import { InspectResponse } from '../../../types'; -import { usersQuery } from './index.gql_query'; +const ID = 'networkUsersQuery'; -const ID = 'usersQuery'; - -export interface UsersArgs { +export interface NetworkUsersArgs { id: string; - inspect: inputsModel.InspectQuery; + inspect: InspectResponse; isInspected: boolean; - loading: boolean; loadPage: (newActivePage: number) => void; + networkUsers: NetworkUsersStrategyResponse['edges']; pageInfo: PageInfoPaginated; refetch: inputsModel.Refetch; + stackByField?: string; totalCount: number; - users: UsersEdges[]; } -export interface OwnProps extends QueryTemplatePaginatedProps { - children: (args: UsersArgs) => React.ReactNode; +interface UseNetworkUsers { + id?: string; + filterQuery?: ESTermQuery | string; + endDate: string; + startDate: string; + skip: boolean; flowTarget: FlowTarget; ip: string; - type: networkModel.NetworkType; } -type UsersProps = OwnProps & PropsFromRedux & WithKibanaProps; +export const useNetworkUsers = ({ + endDate, + filterQuery, + flowTarget, + id = ID, + ip, + skip, + startDate, +}: UseNetworkUsers): [boolean, NetworkUsersArgs] => { + const getNetworkUsersSelector = networkSelectors.usersSelector(); + const { activePage, sort, limit } = useSelector(getNetworkUsersSelector, shallowEqual); + const { data, notifications, uiSettings } = useKibana().services; + const refetch = useRef(noop); + const abortCtrl = useRef(new AbortController()); + const defaultIndex = uiSettings.get(DEFAULT_INDEX_KEY); + const [loading, setLoading] = useState(false); + + const [networkUsersRequest, setNetworkUsersRequest] = useState({ + defaultIndex, + factoryQueryType: NetworkQueries.users, + filterQuery: createFilter(filterQuery), + flowTarget, + ip, + pagination: generateTablePaginationOptions(activePage, limit), + sort, + timerange: { + interval: '12h', + from: startDate ? startDate : '', + to: endDate ? endDate : new Date(Date.now()).toISOString(), + }, + }); + + const wrappedLoadMore = useCallback( + (newActivePage: number) => { + setNetworkUsersRequest((prevRequest) => ({ + ...prevRequest, + pagination: generateTablePaginationOptions(newActivePage, limit), + })); + }, + [limit] + ); -class UsersComponentQuery extends QueryTemplatePaginated< - UsersProps, - GetUsersQuery.Query, - GetUsersQuery.Variables -> { - public render() { - const { - activePage, - children, - endDate, - filterQuery, - flowTarget, - id = ID, - ip, - isInspected, - kibana, - limit, - skip, - sourceId, - startDate, - sort, - } = this.props; - const variables: GetUsersQuery.Variables = { - defaultIndex: kibana.services.uiSettings.get(DEFAULT_INDEX_KEY), - filterQuery: createFilter(filterQuery), - flowTarget, - inspect: isInspected, - ip, - pagination: generateTablePaginationOptions(activePage, limit), - sort, - sourceId, - timerange: { - interval: '12h', - from: startDate!, - to: endDate!, - }, - }; - return ( - - query={usersQuery} - fetchPolicy={getDefaultFetchPolicy()} - notifyOnNetworkStatusChange - skip={skip} - variables={variables} - > - {({ data, loading, fetchMore, networkStatus, refetch }) => { - const users = getOr([], `source.Users.edges`, data); - this.setFetchMore(fetchMore); - this.setFetchMoreOptions((newActivePage: number) => ({ - variables: { - pagination: generateTablePaginationOptions(newActivePage, limit), + const [networkUsersResponse, setNetworkUsersResponse] = useState({ + networkUsers: [], + id, + inspect: { + dsl: [], + response: [], + }, + isInspected: false, + loadPage: wrappedLoadMore, + pageInfo: { + activePage: 0, + fakeTotalCount: 0, + showMorePagesIndicator: false, + }, + refetch: refetch.current, + totalCount: -1, + }); + + const networkUsersSearch = useCallback( + (request: NetworkUsersRequestOptions) => { + let didCancel = false; + const asyncSearch = async () => { + abortCtrl.current = new AbortController(); + setLoading(true); + + const searchSubscription$ = data.search + .search(request, { + strategy: 'securitySolutionSearchStrategy', + abortSignal: abortCtrl.current.signal, + }) + .subscribe({ + next: (response) => { + if (!response.isPartial && !response.isRunning) { + if (!didCancel) { + setLoading(false); + setNetworkUsersResponse((prevResponse) => ({ + ...prevResponse, + networkUsers: response.edges, + inspect: getInspectResponse(response, prevResponse.inspect), + pageInfo: response.pageInfo, + refetch: refetch.current, + totalCount: response.totalCount, + })); + } + searchSubscription$.unsubscribe(); + } else if (response.isPartial && !response.isRunning) { + if (!didCancel) { + setLoading(false); + } + // TODO: Make response error status clearer + notifications.toasts.addWarning(i18n.ERROR_NETWORK_USERS); + searchSubscription$.unsubscribe(); + } }, - updateQuery: (prev, { fetchMoreResult }) => { - if (!fetchMoreResult) { - return prev; + error: (msg) => { + if (!(msg instanceof AbortError)) { + notifications.toasts.addDanger({ + title: i18n.FAIL_NETWORK_USERS, + text: msg.message, + }); } - return { - ...fetchMoreResult, - source: { - ...fetchMoreResult.source, - Users: { - ...fetchMoreResult.source.Users, - edges: [...fetchMoreResult.source.Users.edges], - }, - }, - }; }, - })); - const isLoading = this.isItAValidLoading(loading, variables, networkStatus); - return children({ - id, - inspect: getOr(null, 'source.Users.inspect', data), - isInspected, - loading: isLoading, - loadPage: this.wrappedLoadMore, - pageInfo: getOr({}, 'source.Users.pageInfo', data), - refetch: this.memoizedRefetchQuery(variables, limit, refetch), - totalCount: getOr(-1, 'source.Users.totalCount', data), - users, }); - }} - - ); - } -} - -const makeMapStateToProps = () => { - const getUsersSelector = networkSelectors.usersSelector(); - const getQuery = inputsSelectors.globalQueryByIdSelector(); - const mapStateToProps = (state: State, { id = ID }: OwnProps) => { - const { isInspected } = getQuery(state, id); - return { - ...getUsersSelector(state), - isInspected, - }; - }; + }; + abortCtrl.current.abort(); + asyncSearch(); + refetch.current = asyncSearch; + return () => { + didCancel = true; + abortCtrl.current.abort(); + }; + }, + [data.search, notifications.toasts] + ); - return mapStateToProps; -}; + useEffect(() => { + setNetworkUsersRequest((prevRequest) => { + const myRequest = { + ...prevRequest, + defaultIndex, + filterQuery: createFilter(filterQuery), + pagination: generateTablePaginationOptions(activePage, limit), + sort, + timerange: { + interval: '12h', + from: startDate, + to: endDate, + }, + }; + if (!skip && !deepEqual(prevRequest, myRequest)) { + return myRequest; + } + return prevRequest; + }); + }, [activePage, defaultIndex, endDate, filterQuery, limit, startDate, sort, skip]); -const connector = connect(makeMapStateToProps); + useEffect(() => { + networkUsersSearch(networkUsersRequest); + }, [networkUsersRequest, networkUsersSearch]); -type PropsFromRedux = ConnectedProps; - -export const UsersQuery = compose>( - connector, - withKibana -)(UsersComponentQuery); + return [loading, networkUsersResponse]; +}; diff --git a/x-pack/plugins/security_solution/public/network/containers/users/translations.ts b/x-pack/plugins/security_solution/public/network/containers/users/translations.ts new file mode 100644 index 000000000000..dac260dec984 --- /dev/null +++ b/x-pack/plugins/security_solution/public/network/containers/users/translations.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const ERROR_NETWORK_USERS = i18n.translate( + 'xpack.securitySolution.networkUsers.errorSearchDescription', + { + defaultMessage: `An error has occurred on network users search`, + } +); + +export const FAIL_NETWORK_USERS = i18n.translate( + 'xpack.securitySolution.networkUsers.failSearchDescription', + { + defaultMessage: `Failed to run search on network users`, + } +); diff --git a/x-pack/plugins/security_solution/public/network/pages/ip_details/index.test.tsx b/x-pack/plugins/security_solution/public/network/pages/details/index.test.tsx similarity index 67% rename from x-pack/plugins/security_solution/public/network/pages/ip_details/index.test.tsx rename to x-pack/plugins/security_solution/public/network/pages/details/index.test.tsx index e2e458bcec2f..beae3e4f72aa 100644 --- a/x-pack/plugins/security_solution/public/network/pages/ip_details/index.test.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/details/index.test.tsx @@ -4,10 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { shallow } from 'enzyme'; import React from 'react'; -import { Router } from 'react-router-dom'; -import { ActionCreator } from 'typescript-fsa'; +import { Router, useParams } from 'react-router-dom'; import '../../../common/mock/match_media'; @@ -23,14 +21,24 @@ import { } from '../../../common/mock'; import { useMountAppended } from '../../../common/utils/use_mount_appended'; import { createStore, State } from '../../../common/store'; -import { InputsModelId } from '../../../common/store/inputs/constants'; -import { IPDetailsComponent, IPDetails } from './index'; +import { NetworkDetails } from './index'; type Action = 'PUSH' | 'POP' | 'REPLACE'; const pop: Action = 'POP'; type GlobalWithFetch = NodeJS.Global & { fetch: jest.Mock }; +jest.mock('react-router-dom', () => { + const original = jest.requireActual('react-router-dom'); + + return { + ...original, + useParams: jest.fn(), + }; +}); +jest.mock('../../containers/details', () => ({ + useNetworkDetails: jest.fn().mockReturnValue([true, { networkDetails: {} }]), +})); jest.mock('../../../common/lib/kibana'); jest.mock('../../../common/containers/source'); jest.mock('../../../common/containers/use_global_time', () => ({ @@ -70,34 +78,7 @@ const getMockHistory = (ip: string) => ({ listen: jest.fn(), }); -const to = '2018-03-23T18:49:23.132Z'; -const from = '2018-03-24T03:33:52.253Z'; -const getMockProps = (ip: string) => ({ - to, - from, - isInitializing: false, - setQuery: jest.fn(), - query: { query: 'coolQueryhuh?', language: 'keury' }, - filters: [], - flowTarget: FlowTarget.source, - history: getMockHistory(ip), - location: { - pathname: `/network/ip/${ip}`, - search: '', - state: '', - hash: '', - }, - detailName: ip, - match: { params: { detailName: ip, search: '' }, isExact: true, path: '', url: '' }, - setAbsoluteRangeDatePicker: (jest.fn() as unknown) as ActionCreator<{ - id: InputsModelId; - from: string; - to: string; - }>, - setIpDetailsTablesActivePageToZero: (jest.fn() as unknown) as ActionCreator, -}); - -describe('Ip Details', () => { +describe('Network Details', () => { const mount = useMountAppended(); beforeAll(() => { (useWithSource as jest.Mock).mockReturnValue({ @@ -139,31 +120,41 @@ describe('Ip Details', () => { }); test('it renders', () => { - const wrapper = shallow(); - expect(wrapper.find('[data-test-subj="ip-details-page"]').exists()).toBe(true); - }); - - test('it matches the snapshot', () => { - const wrapper = shallow(); - expect(wrapper).toMatchSnapshot(); + const ip = '123.456.78.90'; + (useParams as jest.Mock).mockReturnValue({ + detailName: ip, + flowTarget: FlowTarget.source, + }); + const wrapper = mount( + + + + + + ); + expect(wrapper.find('[data-test-subj="network-details-page"]').exists()).toBe(true); }); test('it renders ipv6 headline', async () => { + const ip = 'fe80--24ce-f7ff-fede-a571'; (useWithSource as jest.Mock).mockReturnValue({ indicesExist: true, indexPattern: {}, }); - const ip = 'fe80--24ce-f7ff-fede-a571'; + (useParams as jest.Mock).mockReturnValue({ + detailName: ip, + flowTarget: FlowTarget.source, + }); const wrapper = mount( - + ); expect( wrapper - .find('[data-test-subj="ip-details-headline"] [data-test-subj="header-page-title"]') + .find('[data-test-subj="network-details-headline"] [data-test-subj="header-page-title"]') .text() ).toEqual('fe80::24ce:f7ff:fede:a571'); }); diff --git a/x-pack/plugins/security_solution/public/network/pages/ip_details/index.tsx b/x-pack/plugins/security_solution/public/network/pages/details/index.tsx similarity index 69% rename from x-pack/plugins/security_solution/public/network/pages/ip_details/index.tsx rename to x-pack/plugins/security_solution/public/network/pages/details/index.tsx index c9ac1fc7a6e9..085cddf53ff6 100644 --- a/x-pack/plugins/security_solution/public/network/pages/ip_details/index.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/details/index.tsx @@ -5,39 +5,40 @@ */ import { EuiHorizontalRule, EuiSpacer, EuiFlexItem } from '@elastic/eui'; -import React, { useCallback, useEffect } from 'react'; -import { connect, ConnectedProps } from 'react-redux'; +import React, { useCallback, useEffect, useMemo } from 'react'; +import { useDispatch, useSelector, shallowEqual } from 'react-redux'; +import { useParams } from 'react-router-dom'; +import { FlowTarget } from '../../../../common/search_strategy'; import { useGlobalTime } from '../../../common/containers/use_global_time'; import { FiltersGlobal } from '../../../common/components/filters_global'; import { HeaderPage } from '../../../common/components/header_page'; import { LastEventTime } from '../../../common/components/last_event_time'; -import { AnomalyTableProvider } from '../../../common/components/ml/anomaly/anomaly_table_provider'; +import { useAnomaliesTableData } from '../../../common/components/ml/anomaly/use_anomalies_table_data'; import { networkToCriteria } from '../../../common/components/ml/criteria/network_to_criteria'; import { scoreIntervalToDateTime } from '../../../common/components/ml/score/score_interval_to_datetime'; import { AnomaliesNetworkTable } from '../../../common/components/ml/tables/anomalies_network_table'; import { manageQuery } from '../../../common/components/page/manage_query'; import { FlowTargetSelectConnected } from '../../components/flow_target_select_connected'; -import { IpOverview } from '../../components/ip_overview'; +import { IpOverview } from '../../components/details'; import { SiemSearchBar } from '../../../common/components/search_bar'; import { WrapperPage } from '../../../common/components/wrapper_page'; -import { IpOverviewQuery } from '../../containers/ip_overview'; +import { useNetworkDetails } from '../../containers/details'; import { useWithSource } from '../../../common/containers/source'; import { FlowTargetSourceDest, LastEventIndexKey } from '../../../graphql/types'; import { useKibana } from '../../../common/lib/kibana'; import { decodeIpv6 } from '../../../common/lib/helpers'; import { convertToBuildEsQuery } from '../../../common/lib/keury'; import { ConditionalFlexGroup } from '../../pages/navigation/conditional_flex_group'; -import { State, inputsSelectors } from '../../../common/store'; -import { setAbsoluteRangeDatePicker as dispatchAbsoluteRangeDatePicker } from '../../../common/store/inputs/actions'; -import { setIpDetailsTablesActivePageToZero as dispatchIpDetailsTablesActivePageToZero } from '../../store/actions'; +import { inputsSelectors } from '../../../common/store'; +import { setAbsoluteRangeDatePicker } from '../../../common/store/inputs/actions'; +import { setNetworkDetailsTablesActivePageToZero } from '../../store/actions'; import { SpyRoute } from '../../../common/utils/route/spy_routes'; import { OverviewEmpty } from '../../../overview/components/overview_empty'; import { NetworkHttpQueryTable } from './network_http_query_table'; import { NetworkTopCountriesQueryTable } from './network_top_countries_query_table'; import { NetworkTopNFlowQueryTable } from './network_top_n_flow_query_table'; import { TlsQueryTable } from './tls_query_table'; -import { IPDetailsComponentProps } from './types'; import { UsersQueryTable } from './users_query_table'; import { AnomaliesQueryTabBody } from '../../../common/containers/anomalies/anomalies_query_tab_body'; import { esQuery } from '../../../../../../../src/plugins/data/public'; @@ -45,36 +46,42 @@ import { networkModel } from '../../store'; import { SecurityPageName } from '../../../app/types'; export { getBreadcrumbs } from './utils'; -const IpOverviewManage = manageQuery(IpOverview); +const NetworkDetailsManage = manageQuery(IpOverview); -export const IPDetailsComponent: React.FC = ({ - detailName, - filters, - flowTarget, - query, - setAbsoluteRangeDatePicker, - setIpDetailsTablesActivePageToZero, -}) => { +const NetworkDetailsComponent: React.FC = () => { + const dispatch = useDispatch(); const { to, from, setQuery, isInitializing } = useGlobalTime(); + const { detailName, flowTarget } = useParams<{ + detailName: string; + flowTarget: FlowTarget; + }>(); + const getGlobalQuerySelector = inputsSelectors.globalQuerySelector(); + const getGlobalFiltersQuerySelector = inputsSelectors.globalFiltersQuerySelector(); + + const query = useSelector(getGlobalQuerySelector, shallowEqual); + const filters = useSelector(getGlobalFiltersQuerySelector, shallowEqual); + const type = networkModel.NetworkType.details; const narrowDateRange = useCallback( (score, interval) => { const fromTo = scoreIntervalToDateTime(score, interval); - setAbsoluteRangeDatePicker({ - id: 'global', - from: fromTo.from, - to: fromTo.to, - }); + dispatch( + setAbsoluteRangeDatePicker({ + id: 'global', + from: fromTo.from, + to: fromTo.to, + }) + ); }, - [setAbsoluteRangeDatePicker] + [dispatch] ); const { services: { uiSettings }, } = useKibana(); useEffect(() => { - setIpDetailsTablesActivePageToZero(); - }, [detailName, setIpDetailsTablesActivePageToZero]); + dispatch(setNetworkDetailsTablesActivePageToZero()); + }, [detailName, dispatch]); const { docValueFields, indicesExist, indexPattern } = useWithSource(); const ip = decodeIpv6(detailName); @@ -85,8 +92,27 @@ export const IPDetailsComponent: React.FC ({ field: `${flowTarget}.ip`, value: ip }), [ + flowTarget, + ip, + ]); + return ( -
+
{indicesExist ? ( <> @@ -96,50 +122,30 @@ export const IPDetailsComponent: React.FC } title={ip} > - - {({ id, inspect, ipOverviewData, loading, refetch }) => ( - - {({ isLoadingAnomaliesData, anomaliesData }) => ( - - )} - - )} - + data={networkDetails} + anomaliesData={anomaliesData} + loading={loading} + isLoadingAnomaliesData={isLoadingAnomaliesData} + type={type} + flowTarget={flowTarget} + refetch={refetch} + setQuery={setQuery} + startDate={from} + endDate={to} + narrowDateRange={narrowDateRange} + /> @@ -272,25 +278,7 @@ export const IPDetailsComponent: React.FC ); }; -IPDetailsComponent.displayName = 'IPDetailsComponent'; - -const makeMapStateToProps = () => { - const getGlobalQuerySelector = inputsSelectors.globalQuerySelector(); - const getGlobalFiltersQuerySelector = inputsSelectors.globalFiltersQuerySelector(); - - return (state: State) => ({ - query: getGlobalQuerySelector(state), - filters: getGlobalFiltersQuerySelector(state), - }); -}; - -const mapDispatchToProps = { - setAbsoluteRangeDatePicker: dispatchAbsoluteRangeDatePicker, - setIpDetailsTablesActivePageToZero: dispatchIpDetailsTablesActivePageToZero, -}; - -export const connector = connect(makeMapStateToProps, mapDispatchToProps); -type PropsFromRedux = ConnectedProps; +NetworkDetailsComponent.displayName = 'NetworkDetailsComponent'; -export const IPDetails = connector(React.memo(IPDetailsComponent)); +export const NetworkDetails = React.memo(NetworkDetailsComponent); diff --git a/x-pack/plugins/security_solution/public/network/pages/ip_details/network_http_query_table.tsx b/x-pack/plugins/security_solution/public/network/pages/details/network_http_query_table.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/network/pages/ip_details/network_http_query_table.tsx rename to x-pack/plugins/security_solution/public/network/pages/details/network_http_query_table.tsx diff --git a/x-pack/plugins/security_solution/public/network/pages/ip_details/network_top_countries_query_table.tsx b/x-pack/plugins/security_solution/public/network/pages/details/network_top_countries_query_table.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/network/pages/ip_details/network_top_countries_query_table.tsx rename to x-pack/plugins/security_solution/public/network/pages/details/network_top_countries_query_table.tsx diff --git a/x-pack/plugins/security_solution/public/network/pages/ip_details/network_top_n_flow_query_table.tsx b/x-pack/plugins/security_solution/public/network/pages/details/network_top_n_flow_query_table.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/network/pages/ip_details/network_top_n_flow_query_table.tsx rename to x-pack/plugins/security_solution/public/network/pages/details/network_top_n_flow_query_table.tsx diff --git a/x-pack/plugins/security_solution/public/network/pages/ip_details/tls_query_table.tsx b/x-pack/plugins/security_solution/public/network/pages/details/tls_query_table.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/network/pages/ip_details/tls_query_table.tsx rename to x-pack/plugins/security_solution/public/network/pages/details/tls_query_table.tsx diff --git a/x-pack/plugins/security_solution/public/network/pages/ip_details/types.ts b/x-pack/plugins/security_solution/public/network/pages/details/types.ts similarity index 92% rename from x-pack/plugins/security_solution/public/network/pages/ip_details/types.ts rename to x-pack/plugins/security_solution/public/network/pages/details/types.ts index cab6e8e09b20..960df0d5e36b 100644 --- a/x-pack/plugins/security_solution/public/network/pages/ip_details/types.ts +++ b/x-pack/plugins/security_solution/public/network/pages/details/types.ts @@ -16,11 +16,6 @@ import { GlobalTimeArgs } from '../../../common/containers/use_global_time'; export const type = NetworkType.details; -export interface IPDetailsComponentProps { - detailName: string; - flowTarget: FlowTarget; -} - export interface OwnProps { type: NetworkType; startDate: string; diff --git a/x-pack/plugins/security_solution/public/network/pages/details/users_query_table.tsx b/x-pack/plugins/security_solution/public/network/pages/details/users_query_table.tsx new file mode 100644 index 000000000000..a7a819151579 --- /dev/null +++ b/x-pack/plugins/security_solution/public/network/pages/details/users_query_table.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { getOr } from 'lodash/fp'; +import { manageQuery } from '../../../common/components/page/manage_query'; +import { useNetworkUsers } from '../../containers/users'; +import { NetworkComponentsQueryProps } from './types'; +import { UsersTable } from '../../components/users_table'; + +const UsersTableManage = manageQuery(UsersTable); + +export const UsersQueryTable = ({ + endDate, + filterQuery, + flowTarget, + ip, + setQuery, + skip, + startDate, + type, +}: NetworkComponentsQueryProps) => { + const [ + loading, + { id, inspect, isInspected, networkUsers, totalCount, pageInfo, loadPage, refetch }, + ] = useNetworkUsers({ + endDate, + filterQuery, + flowTarget, + ip, + skip, + startDate, + }); + + return ( + + ); +}; + +UsersQueryTable.displayName = 'UsersQueryTable'; diff --git a/x-pack/plugins/security_solution/public/network/pages/ip_details/utils.ts b/x-pack/plugins/security_solution/public/network/pages/details/utils.ts similarity index 94% rename from x-pack/plugins/security_solution/public/network/pages/ip_details/utils.ts rename to x-pack/plugins/security_solution/public/network/pages/details/utils.ts index 9284a808625a..2b5c68c81a9d 100644 --- a/x-pack/plugins/security_solution/public/network/pages/ip_details/utils.ts +++ b/x-pack/plugins/security_solution/public/network/pages/details/utils.ts @@ -8,7 +8,7 @@ import { get, isEmpty } from 'lodash/fp'; import { ChromeBreadcrumb } from '../../../../../../../src/core/public'; import { decodeIpv6 } from '../../../common/lib/helpers'; -import { getIPDetailsUrl } from '../../../common/components/link_to/redirect_to_network'; +import { getNetworkDetailsUrl } from '../../../common/components/link_to/redirect_to_network'; import { networkModel } from '../../store'; import * as i18n from '../translations'; import { NetworkRouteType } from '../navigation/types'; @@ -46,7 +46,7 @@ export const getBreadcrumbs = ( { text: decodeIpv6(params.detailName), href: getUrlForApp(`${APP_ID}:${SecurityPageName.network}`, { - path: getIPDetailsUrl( + path: getNetworkDetailsUrl( params.detailName, params.flowTarget, !isEmpty(search[0]) ? search[0] : '' diff --git a/x-pack/plugins/security_solution/public/network/pages/index.tsx b/x-pack/plugins/security_solution/public/network/pages/index.tsx index 07abe7bc8c20..9e796b6f01df 100644 --- a/x-pack/plugins/security_solution/public/network/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/index.tsx @@ -11,7 +11,7 @@ import { useMlCapabilities } from '../../common/components/ml/hooks/use_ml_capab import { hasMlUserPermissions } from '../../../common/machine_learning/has_ml_user_permissions'; import { FlowTarget } from '../../graphql/types'; -import { IPDetails } from './ip_details'; +import { NetworkDetails } from './details'; import { Network } from './network'; import { getNetworkRoutePath } from './navigation'; import { NetworkRouteType } from './navigation/types'; @@ -49,14 +49,9 @@ const NetworkContainerComponent: React.FC = () => { hasMlUserPermissions={userHasMlUserPermissions} /> - } - /> + + + - - - - - -
-`; diff --git a/x-pack/plugins/security_solution/public/network/pages/ip_details/users_query_table.tsx b/x-pack/plugins/security_solution/public/network/pages/ip_details/users_query_table.tsx deleted file mode 100644 index 4071790b4208..000000000000 --- a/x-pack/plugins/security_solution/public/network/pages/ip_details/users_query_table.tsx +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import { getOr } from 'lodash/fp'; -import { manageQuery } from '../../../common/components/page/manage_query'; -import { UsersQuery } from '../../containers/users'; -import { NetworkComponentsQueryProps } from './types'; -import { UsersTable } from '../../components/users_table'; - -const UsersTableManage = manageQuery(UsersTable); - -export const UsersQueryTable = ({ - endDate, - filterQuery, - flowTarget, - ip, - setQuery, - skip, - startDate, - type, -}: NetworkComponentsQueryProps) => ( - - {({ id, inspect, isInspected, users, totalCount, pageInfo, loading, loadPage, refetch }) => ( - - )} - -); - -UsersQueryTable.displayName = 'UsersQueryTable'; diff --git a/x-pack/plugins/security_solution/public/network/store/actions.ts b/x-pack/plugins/security_solution/public/network/store/actions.ts index 44a0b7ce1ad1..9c0242741304 100644 --- a/x-pack/plugins/security_solution/public/network/store/actions.ts +++ b/x-pack/plugins/security_solution/public/network/store/actions.ts @@ -11,11 +11,11 @@ const actionCreator = actionCreatorFactory('x-pack/security_solution/local/netwo export const updateNetworkTable = actionCreator<{ networkType: networkModel.NetworkType; - tableType: networkModel.NetworkTableType | networkModel.IpDetailsTableType; + tableType: networkModel.NetworkTableType | networkModel.NetworkDetailsTableType; updates: networkModel.TableUpdates; }>('UPDATE_NETWORK_TABLE'); -export const setIpDetailsTablesActivePageToZero = actionCreator( +export const setNetworkDetailsTablesActivePageToZero = actionCreator( 'SET_IP_DETAILS_TABLES_ACTIVE_PAGE_TO_ZERO' ); diff --git a/x-pack/plugins/security_solution/public/network/store/helpers.test.ts b/x-pack/plugins/security_solution/public/network/store/helpers.test.ts index a3a2a9b7f539..944939074693 100644 --- a/x-pack/plugins/security_solution/public/network/store/helpers.test.ts +++ b/x-pack/plugins/security_solution/public/network/store/helpers.test.ts @@ -9,11 +9,11 @@ import { FlowTarget, NetworkDnsFields, NetworkTopTablesFields, - TlsFields, - UsersFields, -} from '../../graphql/types'; + NetworkTlsFields, + NetworkUsersFields, +} from '../../../common/search_strategy'; import { DEFAULT_TABLE_LIMIT } from '../../common/store/constants'; -import { NetworkModel, NetworkTableType, IpDetailsTableType, NetworkType } from './model'; +import { NetworkModel, NetworkTableType, NetworkDetailsTableType, NetworkType } from './model'; import { setNetworkQueriesActivePageToZero } from './helpers'; export const mockNetworkState: NetworkModel = { @@ -64,7 +64,7 @@ export const mockNetworkState: NetworkModel = { activePage: 2, limit: DEFAULT_TABLE_LIMIT, sort: { - field: TlsFields._id, + field: NetworkTlsFields._id, direction: Direction.desc, }, }, @@ -81,7 +81,7 @@ export const mockNetworkState: NetworkModel = { }, details: { queries: { - [IpDetailsTableType.topCountriesSource]: { + [NetworkDetailsTableType.topCountriesSource]: { activePage: 7, limit: DEFAULT_TABLE_LIMIT, sort: { @@ -89,7 +89,7 @@ export const mockNetworkState: NetworkModel = { direction: Direction.desc, }, }, - [IpDetailsTableType.topCountriesDestination]: { + [NetworkDetailsTableType.topCountriesDestination]: { activePage: 3, limit: DEFAULT_TABLE_LIMIT, sort: { @@ -97,7 +97,7 @@ export const mockNetworkState: NetworkModel = { direction: Direction.desc, }, }, - [IpDetailsTableType.topNFlowSource]: { + [NetworkDetailsTableType.topNFlowSource]: { activePage: 7, limit: DEFAULT_TABLE_LIMIT, sort: { @@ -105,7 +105,7 @@ export const mockNetworkState: NetworkModel = { direction: Direction.desc, }, }, - [IpDetailsTableType.topNFlowDestination]: { + [NetworkDetailsTableType.topNFlowDestination]: { activePage: 3, limit: DEFAULT_TABLE_LIMIT, sort: { @@ -113,23 +113,23 @@ export const mockNetworkState: NetworkModel = { direction: Direction.desc, }, }, - [IpDetailsTableType.tls]: { + [NetworkDetailsTableType.tls]: { activePage: 2, limit: DEFAULT_TABLE_LIMIT, sort: { - field: TlsFields._id, + field: NetworkTlsFields._id, direction: Direction.desc, }, }, - [IpDetailsTableType.users]: { + [NetworkDetailsTableType.users]: { activePage: 6, limit: DEFAULT_TABLE_LIMIT, sort: { - field: UsersFields.name, + field: NetworkUsersFields.name, direction: Direction.asc, }, }, - [IpDetailsTableType.http]: { + [NetworkDetailsTableType.http]: { activePage: 0, limit: DEFAULT_TABLE_LIMIT, sort: { direction: Direction.desc }, @@ -199,17 +199,17 @@ describe('Network redux store', () => { test('set activePage to zero for all queries in ip details ', () => { expect(setNetworkQueriesActivePageToZero(mockNetworkState, NetworkType.details)).toEqual({ - [IpDetailsTableType.topNFlowSource]: { + [NetworkDetailsTableType.topNFlowSource]: { activePage: 0, limit: 10, sort: { field: 'bytes_out', direction: 'desc' }, }, - [IpDetailsTableType.topNFlowDestination]: { + [NetworkDetailsTableType.topNFlowDestination]: { activePage: 0, limit: 10, sort: { field: 'bytes_out', direction: 'desc' }, }, - [IpDetailsTableType.topCountriesDestination]: { + [NetworkDetailsTableType.topCountriesDestination]: { activePage: 0, limit: 10, sort: { @@ -217,7 +217,7 @@ describe('Network redux store', () => { field: 'bytes_out', }, }, - [IpDetailsTableType.topCountriesSource]: { + [NetworkDetailsTableType.topCountriesSource]: { activePage: 0, limit: 10, sort: { @@ -225,19 +225,19 @@ describe('Network redux store', () => { field: 'bytes_out', }, }, - [IpDetailsTableType.http]: { + [NetworkDetailsTableType.http]: { activePage: 0, limit: 10, sort: { direction: 'desc', }, }, - [IpDetailsTableType.tls]: { + [NetworkDetailsTableType.tls]: { activePage: 0, limit: 10, sort: { field: '_id', direction: 'desc' }, }, - [IpDetailsTableType.users]: { + [NetworkDetailsTableType.users]: { activePage: 0, limit: 10, sort: { field: 'name', direction: 'asc' }, diff --git a/x-pack/plugins/security_solution/public/network/store/helpers.ts b/x-pack/plugins/security_solution/public/network/store/helpers.ts index 938de1dedf0b..e93e5ada0359 100644 --- a/x-pack/plugins/security_solution/public/network/store/helpers.ts +++ b/x-pack/plugins/security_solution/public/network/store/helpers.ts @@ -8,9 +8,9 @@ import { NetworkModel, NetworkType, NetworkTableType, - IpDetailsTableType, + NetworkDetailsTableType, NetworkQueries, - IpOverviewQueries, + NetworkDetailsQueries, } from './model'; import { DEFAULT_TABLE_ACTIVE_PAGE } from '../../common/store/constants'; @@ -48,34 +48,34 @@ export const setNetworkPageQueriesActivePageToZero = (state: NetworkModel): Netw export const setNetworkDetailsQueriesActivePageToZero = ( state: NetworkModel -): IpOverviewQueries => ({ +): NetworkDetailsQueries => ({ ...state.details.queries, - [IpDetailsTableType.topCountriesSource]: { - ...state.details.queries[IpDetailsTableType.topCountriesSource], + [NetworkDetailsTableType.topCountriesSource]: { + ...state.details.queries[NetworkDetailsTableType.topCountriesSource], activePage: DEFAULT_TABLE_ACTIVE_PAGE, }, - [IpDetailsTableType.topCountriesDestination]: { - ...state.details.queries[IpDetailsTableType.topCountriesDestination], + [NetworkDetailsTableType.topCountriesDestination]: { + ...state.details.queries[NetworkDetailsTableType.topCountriesDestination], activePage: DEFAULT_TABLE_ACTIVE_PAGE, }, - [IpDetailsTableType.topNFlowSource]: { - ...state.details.queries[IpDetailsTableType.topNFlowSource], + [NetworkDetailsTableType.topNFlowSource]: { + ...state.details.queries[NetworkDetailsTableType.topNFlowSource], activePage: DEFAULT_TABLE_ACTIVE_PAGE, }, - [IpDetailsTableType.topNFlowDestination]: { - ...state.details.queries[IpDetailsTableType.topNFlowDestination], + [NetworkDetailsTableType.topNFlowDestination]: { + ...state.details.queries[NetworkDetailsTableType.topNFlowDestination], activePage: DEFAULT_TABLE_ACTIVE_PAGE, }, - [IpDetailsTableType.tls]: { - ...state.details.queries[IpDetailsTableType.tls], + [NetworkDetailsTableType.tls]: { + ...state.details.queries[NetworkDetailsTableType.tls], activePage: DEFAULT_TABLE_ACTIVE_PAGE, }, - [IpDetailsTableType.users]: { - ...state.details.queries[IpDetailsTableType.users], + [NetworkDetailsTableType.users]: { + ...state.details.queries[NetworkDetailsTableType.users], activePage: DEFAULT_TABLE_ACTIVE_PAGE, }, - [IpDetailsTableType.http]: { - ...state.details.queries[IpDetailsTableType.http], + [NetworkDetailsTableType.http]: { + ...state.details.queries[NetworkDetailsTableType.http], activePage: DEFAULT_TABLE_ACTIVE_PAGE, }, }); @@ -83,7 +83,7 @@ export const setNetworkDetailsQueriesActivePageToZero = ( export const setNetworkQueriesActivePageToZero = ( state: NetworkModel, type: NetworkType -): NetworkQueries | IpOverviewQueries => { +): NetworkQueries | NetworkDetailsQueries => { if (type === NetworkType.page) { return setNetworkPageQueriesActivePageToZero(state); } else if (type === NetworkType.details) { diff --git a/x-pack/plugins/security_solution/public/network/store/model.ts b/x-pack/plugins/security_solution/public/network/store/model.ts index 4ddfb8402497..f2daddbd5c3d 100644 --- a/x-pack/plugins/security_solution/public/network/store/model.ts +++ b/x-pack/plugins/security_solution/public/network/store/model.ts @@ -5,13 +5,14 @@ */ import { + Direction, FlowTarget, - NetworkDnsSortField, - NetworkHttpSortField, - NetworkTopTablesSortField, - TlsSortField, - UsersSortField, -} from '../../graphql/types'; + NetworkDnsFields, + NetworkTopTablesFields, + NetworkTlsFields, + NetworkUsersFields, + SortField, +} from '../../../common/search_strategy'; export enum NetworkType { page = 'page', @@ -30,22 +31,22 @@ export enum NetworkTableType { } export type TopNTableType = - | IpDetailsTableType.topNFlowDestination - | IpDetailsTableType.topNFlowSource + | NetworkDetailsTableType.topNFlowDestination + | NetworkDetailsTableType.topNFlowSource | NetworkTableType.topNFlowDestination | NetworkTableType.topNFlowSource; export type TopCountriesTableType = - | IpDetailsTableType.topCountriesDestination - | IpDetailsTableType.topCountriesSource + | NetworkDetailsTableType.topCountriesDestination + | NetworkDetailsTableType.topCountriesSource | NetworkTableType.topCountriesDestination | NetworkTableType.topCountriesSource; -export type TopTlsTableType = IpDetailsTableType.tls | NetworkTableType.tls; +export type TopTlsTableType = NetworkDetailsTableType.tls | NetworkTableType.tls; -export type HttpTableType = IpDetailsTableType.http | NetworkTableType.http; +export type HttpTableType = NetworkDetailsTableType.http | NetworkTableType.http; -export enum IpDetailsTableType { +export enum NetworkDetailsTableType { http = 'http', tls = 'tls', topCountriesDestination = 'topCountriesDestination', @@ -55,7 +56,7 @@ export enum IpDetailsTableType { users = 'users', } -export type AllNetworkTables = NetworkTableType | IpDetailsTableType; +export type AllNetworkTables = NetworkTableType | NetworkDetailsTableType; export interface BasicQueryPaginated { activePage: number; @@ -64,24 +65,26 @@ export interface BasicQueryPaginated { // Network Page Models export interface TopNFlowQuery extends BasicQueryPaginated { - sort: NetworkTopTablesSortField; + sort: SortField; } export interface TopCountriesQuery extends BasicQueryPaginated { - sort: NetworkTopTablesSortField; + sort: SortField; } export interface DnsQuery extends BasicQueryPaginated { - sort: NetworkDnsSortField; + sort: SortField; isPtrIncluded: boolean; } export interface TlsQuery extends BasicQueryPaginated { - sort: TlsSortField; + sort: SortField; } export interface HttpQuery extends BasicQueryPaginated { - sort: NetworkHttpSortField; + sort: { + direction: Direction; + }; } export interface TableUpdates { @@ -89,11 +92,11 @@ export interface TableUpdates { limit?: number; isPtrIncluded?: boolean; sort?: - | NetworkDnsSortField - | NetworkHttpSortField - | NetworkTopTablesSortField - | TlsSortField - | UsersSortField; + | SortField + | HttpQuery['sort'] + | SortField + | SortField + | SortField; } export interface NetworkQueries { @@ -111,23 +114,23 @@ export interface NetworkPageModel { queries: NetworkQueries; } -export interface UsersQuery extends BasicQueryPaginated { - sort: UsersSortField; +export interface NetworkUsersQuery extends BasicQueryPaginated { + sort: SortField; } -export interface IpOverviewQueries { - [IpDetailsTableType.http]: HttpQuery; - [IpDetailsTableType.tls]: TlsQuery; - [IpDetailsTableType.topCountriesDestination]: TopCountriesQuery; - [IpDetailsTableType.topCountriesSource]: TopCountriesQuery; - [IpDetailsTableType.topNFlowDestination]: TopNFlowQuery; - [IpDetailsTableType.topNFlowSource]: TopNFlowQuery; - [IpDetailsTableType.users]: UsersQuery; +export interface NetworkDetailsQueries { + [NetworkDetailsTableType.http]: HttpQuery; + [NetworkDetailsTableType.tls]: TlsQuery; + [NetworkDetailsTableType.topCountriesDestination]: TopCountriesQuery; + [NetworkDetailsTableType.topCountriesSource]: TopCountriesQuery; + [NetworkDetailsTableType.topNFlowDestination]: TopNFlowQuery; + [NetworkDetailsTableType.topNFlowSource]: TopNFlowQuery; + [NetworkDetailsTableType.users]: NetworkUsersQuery; } export interface NetworkDetailsModel { flowTarget: FlowTarget; - queries: IpOverviewQueries; + queries: NetworkDetailsQueries; } export interface NetworkModel { diff --git a/x-pack/plugins/security_solution/public/network/store/reducer.ts b/x-pack/plugins/security_solution/public/network/store/reducer.ts index 380cd660f3e3..e3eb2acc78d6 100644 --- a/x-pack/plugins/security_solution/public/network/store/reducer.ts +++ b/x-pack/plugins/security_solution/public/network/store/reducer.ts @@ -11,13 +11,13 @@ import { FlowTarget, NetworkDnsFields, NetworkTopTablesFields, - TlsFields, - UsersFields, -} from '../../graphql/types'; + NetworkTlsFields, + NetworkUsersFields, +} from '../../../common/search_strategy'; import { DEFAULT_TABLE_ACTIVE_PAGE, DEFAULT_TABLE_LIMIT } from '../../common/store/constants'; import { - setIpDetailsTablesActivePageToZero, + setNetworkDetailsTablesActivePageToZero, setNetworkTablesActivePageToZero, updateNetworkTable, } from './actions'; @@ -25,7 +25,7 @@ import { setNetworkDetailsQueriesActivePageToZero, setNetworkPageQueriesActivePageToZero, } from './helpers'; -import { IpDetailsTableType, NetworkModel, NetworkTableType } from './model'; +import { NetworkDetailsTableType, NetworkModel, NetworkTableType } from './model'; export type NetworkState = NetworkModel; @@ -68,7 +68,7 @@ export const initialNetworkState: NetworkState = { activePage: DEFAULT_TABLE_ACTIVE_PAGE, limit: DEFAULT_TABLE_LIMIT, sort: { - field: TlsFields._id, + field: NetworkTlsFields._id, direction: Direction.desc, }, }, @@ -96,14 +96,14 @@ export const initialNetworkState: NetworkState = { }, details: { queries: { - [IpDetailsTableType.http]: { + [NetworkDetailsTableType.http]: { activePage: DEFAULT_TABLE_ACTIVE_PAGE, limit: DEFAULT_TABLE_LIMIT, sort: { direction: Direction.desc, }, }, - [IpDetailsTableType.topCountriesSource]: { + [NetworkDetailsTableType.topCountriesSource]: { activePage: DEFAULT_TABLE_ACTIVE_PAGE, limit: DEFAULT_TABLE_LIMIT, sort: { @@ -111,7 +111,7 @@ export const initialNetworkState: NetworkState = { direction: Direction.desc, }, }, - [IpDetailsTableType.topCountriesDestination]: { + [NetworkDetailsTableType.topCountriesDestination]: { activePage: DEFAULT_TABLE_ACTIVE_PAGE, limit: DEFAULT_TABLE_LIMIT, sort: { @@ -119,7 +119,7 @@ export const initialNetworkState: NetworkState = { direction: Direction.desc, }, }, - [IpDetailsTableType.topNFlowSource]: { + [NetworkDetailsTableType.topNFlowSource]: { activePage: DEFAULT_TABLE_ACTIVE_PAGE, limit: DEFAULT_TABLE_LIMIT, sort: { @@ -127,7 +127,7 @@ export const initialNetworkState: NetworkState = { direction: Direction.desc, }, }, - [IpDetailsTableType.topNFlowDestination]: { + [NetworkDetailsTableType.topNFlowDestination]: { activePage: DEFAULT_TABLE_ACTIVE_PAGE, limit: DEFAULT_TABLE_LIMIT, sort: { @@ -135,19 +135,19 @@ export const initialNetworkState: NetworkState = { direction: Direction.desc, }, }, - [IpDetailsTableType.tls]: { + [NetworkDetailsTableType.tls]: { activePage: DEFAULT_TABLE_ACTIVE_PAGE, limit: DEFAULT_TABLE_LIMIT, sort: { - field: TlsFields._id, + field: NetworkTlsFields._id, direction: Direction.desc, }, }, - [IpDetailsTableType.users]: { + [NetworkDetailsTableType.users]: { activePage: DEFAULT_TABLE_ACTIVE_PAGE, limit: DEFAULT_TABLE_LIMIT, sort: { - field: UsersFields.name, + field: NetworkUsersFields.name, direction: Direction.asc, }, }, @@ -181,7 +181,7 @@ export const networkReducer = reducerWithInitialState(initialNetworkState) queries: setNetworkDetailsQueriesActivePageToZero(state), }, })) - .case(setIpDetailsTablesActivePageToZero, (state) => ({ + .case(setNetworkDetailsTablesActivePageToZero, (state) => ({ ...state, details: { ...state.details, diff --git a/x-pack/plugins/security_solution/public/network/store/selectors.ts b/x-pack/plugins/security_solution/public/network/store/selectors.ts index 0246305092a3..833cb3a69789 100644 --- a/x-pack/plugins/security_solution/public/network/store/selectors.ts +++ b/x-pack/plugins/security_solution/public/network/store/selectors.ts @@ -11,7 +11,7 @@ import { FlowTargetSourceDest } from '../../../common/search_strategy/security_s import { State } from '../../common/store/types'; import { initialNetworkState } from './reducer'; import { - IpDetailsTableType, + NetworkDetailsTableType, NetworkDetailsModel, NetworkPageModel, NetworkTableType, @@ -36,7 +36,7 @@ const selectTopNFlowByType = ( ) => { const ft = flowTarget === FlowTargetSourceDest.source ? 'topNFlowSource' : 'topNFlowDestination'; const nFlowType = - networkType === NetworkType.page ? NetworkTableType[ft] : IpDetailsTableType[ft]; + networkType === NetworkType.page ? NetworkTableType[ft] : NetworkDetailsTableType[ft]; return ( get([networkType, 'queries', nFlowType], state.network) || get([networkType, 'queries', nFlowType], initialNetworkState) @@ -46,7 +46,8 @@ const selectTopNFlowByType = ( export const topNFlowSelector = () => createSelector(selectTopNFlowByType, (topNFlowQueries) => topNFlowQueries); const selectTlsByType = (state: State, networkType: NetworkType): TlsQuery => { - const tlsType = networkType === NetworkType.page ? NetworkTableType.tls : IpDetailsTableType.tls; + const tlsType = + networkType === NetworkType.page ? NetworkTableType.tls : NetworkDetailsTableType.tls; return ( get([networkType, 'queries', tlsType], state.network) || get([networkType, 'queries', tlsType], initialNetworkState) @@ -63,7 +64,7 @@ const selectTopCountriesByType = ( const ft = flowTarget === FlowTargetSourceDest.source ? 'topCountriesSource' : 'topCountriesDestination'; const nFlowType = - networkType === NetworkType.page ? NetworkTableType[ft] : IpDetailsTableType[ft]; + networkType === NetworkType.page ? NetworkTableType[ft] : NetworkDetailsTableType[ft]; return ( get([networkType, 'queries', nFlowType], state.network) || @@ -76,7 +77,7 @@ export const topCountriesSelector = () => const selectHttpByType = (state: State, networkType: NetworkType): HttpQuery => { const httpType = - networkType === NetworkType.page ? NetworkTableType.http : IpDetailsTableType.http; + networkType === NetworkType.page ? NetworkTableType.http : NetworkDetailsTableType.http; return ( get([networkType, 'queries', httpType], state.network) || get([networkType, 'queries', httpType], initialNetworkState) diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx index 08f3f01bc99f..7bbd7f553ac4 100644 --- a/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/index.tsx @@ -10,6 +10,7 @@ import lightTheme from '@elastic/eui/dist/eui_theme_light.json'; import { getOr } from 'lodash/fp'; import React, { useCallback, useMemo } from 'react'; +import { HostItem } from '../../../../common/search_strategy'; import { DEFAULT_DARK_MODE } from '../../../../common/constants'; import { DescriptionList } from '../../../../common/utility_types'; import { useUiSetting$ } from '../../../common/lib/kibana'; @@ -19,9 +20,8 @@ import { hostIdRenderer, } from '../../../timelines/components/field_renderers/field_renderers'; import { InspectButton, InspectButtonContainer } from '../../../common/components/inspect'; -import { HostItem } from '../../../graphql/types'; import { Loader } from '../../../common/components/loader'; -import { IPDetailsLink } from '../../../common/components/links'; +import { NetworkDetailsLink } from '../../../common/components/links'; import { hasMlUserPermissions } from '../../../../common/machine_learning/has_ml_user_permissions'; import { useMlCapabilities } from '../../../common/components/ml/hooks/use_ml_capabilities'; import { AnomalyScores } from '../../../common/components/ml/score/anomaly_scores'; @@ -154,7 +154,7 @@ export const HostOverview = React.memo( rowItems={getOr([], 'host.ip', data)} attrName={'host.ip'} idPrefix="host-overview" - render={(ip) => (ip != null ? : getEmptyTagValue())} + render={(ip) => (ip != null ? : getEmptyTagValue())} /> ), }, diff --git a/x-pack/plugins/security_solution/public/overview/components/host_overview/mock.ts b/x-pack/plugins/security_solution/public/overview/components/host_overview/mock.ts index c24cb20e9087..7fe9ac139e12 100644 --- a/x-pack/plugins/security_solution/public/overview/components/host_overview/mock.ts +++ b/x-pack/plugins/security_solution/public/overview/components/host_overview/mock.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { HostsData } from '../../../graphql/types'; +import { HostsStrategyResponse } from '../../../../common/search_strategy'; -export const mockData: { Hosts: HostsData; DateFields: string[] } = { +export const mockData: { Hosts: HostsStrategyResponse; DateFields: string[] } = { Hosts: { totalCount: 1, edges: [ @@ -47,6 +47,7 @@ export const mockData: { Hosts: HostsData; DateFields: string[] } = { fakeTotalCount: 50, showMorePagesIndicator: true, }, + rawResponse: {} as HostsStrategyResponse['rawResponse'], }, DateFields: ['lastBeat'], }; diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index 1017cbb6a2c6..10bbbbfa7271 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -21,7 +21,7 @@ import { import { Storage } from '../../../../src/plugins/kibana_utils/public'; import { initTelemetry } from './common/lib/telemetry'; import { KibanaServices } from './common/lib/kibana/services'; -import { jiraActionType, resilientActionType } from './common/lib/connectors'; +import { resilientActionType } from './common/lib/connectors'; import { PluginSetup, PluginStart, @@ -96,7 +96,6 @@ export class Plugin implements IPlugin { diff --git a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.test.tsx index c3b67e330045..bf89cc7fa908 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.test.tsx @@ -7,7 +7,6 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { FlowTarget, GetIpOverviewQuery, HostEcsFields } from '../../../graphql/types'; import { TestProviders } from '../../../common/mock'; import '../../../common/mock/match_media'; import { getEmptyValue } from '../../../common/components/empty_value'; @@ -23,10 +22,10 @@ import { DEFAULT_MORE_MAX_HEIGHT, MoreContainer, } from './field_renderers'; -import { mockData } from '../../../network/components/ip_overview/mock'; +import { mockData } from '../../../network/components/details/mock'; import { useMountAppended } from '../../../common/utils/use_mount_appended'; - -type AutonomousSystem = GetIpOverviewQuery.AutonomousSystem; +import { AutonomousSystem, FlowTarget } from '../../../../common/search_strategy'; +import { HostEcs } from '../../../../common/ecs/host'; describe('Field Renderers', () => { const mount = useMountAppended(); @@ -98,15 +97,15 @@ describe('Field Renderers', () => { }); describe('#hostIdRenderer', () => { - const emptyIdHost: Partial = { + const emptyIdHost: Partial = { name: ['test'], - id: null, + id: undefined, ip: ['10.10.10.10'], }; - const emptyIpHost: Partial = { + const emptyIpHost: Partial = { name: ['test'], id: ['test'], - ip: null, + ip: undefined, }; test('it renders correctly against snapshot', () => { const wrapper = shallow(hostNameRenderer(mockData.complete.host, '10.10.10.10')); @@ -136,18 +135,18 @@ describe('Field Renderers', () => { }); describe('#hostNameRenderer', () => { - const emptyIdHost: Partial = { + const emptyIdHost: Partial = { name: ['test'], - id: null, + id: undefined, ip: ['10.10.10.10'], }; - const emptyIpHost: Partial = { + const emptyIpHost: Partial = { name: ['test'], id: ['test'], - ip: null, + ip: undefined, }; - const emptyNameHost: Partial = { - name: null, + const emptyNameHost: Partial = { + name: undefined, id: ['test'], ip: ['10.10.10.10'], }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.tsx b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.tsx index 80fe7cb33779..1f76c2840e8b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/field_renderers.tsx @@ -10,12 +10,12 @@ import { getOr } from 'lodash/fp'; import React, { Fragment, useState } from 'react'; import styled from 'styled-components'; +import { HostEcs } from '../../../../common/ecs/host'; import { AutonomousSystem, FlowTarget, - HostEcsFields, - IpOverviewData, -} from '../../../graphql/types'; + NetworkDetailsStrategyResponse, +} from '../../../../common/search_strategy'; import { escapeDataProviderId } from '../../../common/components/drag_and_drop/helpers'; import { DefaultDraggable } from '../../../common/components/draggables'; import { getEmptyTagValue } from '../../../common/components/empty_value'; @@ -27,7 +27,7 @@ import { ReputationLinkSetting, } from '../../../common/components/links'; import { Spacer } from '../../../common/components/page'; -import * as i18n from '../../../network/components/ip_overview/translations'; +import * as i18n from '../../../network/components/details/translations'; const DraggableContainerFlexGroup = styled(EuiFlexGroup)` flex-grow: unset; @@ -38,7 +38,10 @@ export const IpOverviewId = 'ip-overview'; /** The default max-height of the popover used to show "+n More" items (e.g. `+9 More`) */ export const DEFAULT_MORE_MAX_HEIGHT = '200px'; -export const locationRenderer = (fieldNames: string[], data: IpOverviewData): React.ReactElement => +export const locationRenderer = ( + fieldNames: string[], + data: NetworkDetailsStrategyResponse['networkDetails'] +): React.ReactElement => fieldNames.length > 0 && fieldNames.every((fieldName) => getOr(null, fieldName, data)) ? ( {fieldNames.map((fieldName, index) => { @@ -92,7 +95,7 @@ export const autonomousSystemRenderer = ( ); interface HostIdRendererTypes { - host: HostEcsFields; + host: HostEcs; ipFilter?: string; noLink?: boolean; } @@ -124,8 +127,12 @@ export const hostIdRenderer = ({ getEmptyTagValue() ); -export const hostNameRenderer = (host: HostEcsFields, ipFilter?: string): React.ReactElement => - host.name && host.name[0] && host.ip && (!(ipFilter != null) || host.ip.includes(ipFilter)) ? ( +export const hostNameRenderer = (host?: HostEcs, ipFilter?: string): React.ReactElement => + host && + host.name && + host.name[0] && + host.ip && + (!(ipFilter != null) || host.ip.includes(ipFilter)) ? ( JSX.Element; -// TODO: This causes breaks between elements until the ticket below is fixed -// https://github.com/elastic/ingest-dev/issues/474 export const DefaultFieldRendererComponent: React.FC = ({ attrName, displayCount = 1, diff --git a/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.tsx index a0678fb4a437..e4148b558143 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/formatted_ip/index.tsx @@ -13,7 +13,7 @@ import { } from '../../../common/components/drag_and_drop/draggable_wrapper'; import { escapeDataProviderId } from '../../../common/components/drag_and_drop/helpers'; import { getOrEmptyTagFromValue } from '../../../common/components/empty_value'; -import { IPDetailsLink } from '../../../common/components/links'; +import { NetworkDetailsLink } from '../../../common/components/links'; import { parseQueryValue } from '../../../timelines/components/timeline/body/renderers/parse_query_value'; import { DataProvider, @@ -122,7 +122,7 @@ const AddressLinksComponent: React.FC<{ /> ) : ( - + ) } truncate={truncate} diff --git a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts index 6a8d56ff41a0..0ec0db9f3277 100644 --- a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts +++ b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts @@ -12,12 +12,10 @@ import { import { AgentService, IngestManagerStartContract } from '../../../ingest_manager/server'; import { getPackagePolicyCreateCallback } from './ingest_integration'; import { ManifestManager } from './services/artifacts'; -import { ExceptionListClient } from '../../../lists/server'; export type EndpointAppContextServiceStartContract = Partial< Pick > & { - exceptionsListService: ExceptionListClient; logger: Logger; manifestManager?: ManifestManager; registerIngestCallback?: IngestManagerStartContract['registerExternalCallback']; @@ -32,11 +30,9 @@ export class EndpointAppContextService { private agentService: AgentService | undefined; private manifestManager: ManifestManager | undefined; private savedObjectsStart: SavedObjectsServiceStart | undefined; - private exceptionsListService: ExceptionListClient | undefined; public start(dependencies: EndpointAppContextServiceStartContract) { this.agentService = dependencies.agentService; - this.exceptionsListService = dependencies.exceptionsListService; this.manifestManager = dependencies.manifestManager; this.savedObjectsStart = dependencies.savedObjectsStart; @@ -54,13 +50,6 @@ export class EndpointAppContextService { return this.agentService; } - public getExceptionsList() { - if (!this.exceptionsListService) { - throw new Error('exceptionsListService not set'); - } - return this.exceptionsListService; - } - public getManifestManager(): ManifestManager | undefined { return this.manifestManager; } diff --git a/x-pack/plugins/security_solution/server/endpoint/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/mocks.ts index 03754c7be7a5..b5f35a198fa9 100644 --- a/x-pack/plugins/security_solution/server/endpoint/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/mocks.ts @@ -21,7 +21,6 @@ import { import { ManifestManager } from './services/artifacts/manifest_manager/manifest_manager'; import { getManifestManagerMock } from './services/artifacts/manifest_manager/manifest_manager.mock'; import { EndpointAppContext } from './types'; -import { listMock } from '../../../lists/server/mocks'; /** * Creates a mocked EndpointAppContext. @@ -59,7 +58,6 @@ export const createMockEndpointAppContextServiceStartContract = (): jest.Mocked< > => { return { agentService: createMockAgentService(), - exceptionsListService: listMock.getExceptionListClient(), logger: loggingSystemMock.create().get('mock_endpoint_app_context'), savedObjectsStart: savedObjectsServiceMock.createStartContract(), manifestManager: getManifestManagerMock(), diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts index 161a31e2ec93..144c536b4e45 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts @@ -9,11 +9,12 @@ import { SearchResponse } from 'elasticsearch'; import { schema } from '@kbn/config-schema'; import Boom from 'boom'; -import { metadataIndexPattern } from '../../../../common/endpoint/constants'; +import { metadataCurrentIndexPattern } from '../../../../common/endpoint/constants'; import { getESQueryHostMetadataByID, kibanaRequestToMetadataListESQuery } from './query_builders'; import { HostInfo, HostMetadata, + HostMetadataDetails, HostResultList, HostStatus, } from '../../../../common/endpoint/types'; @@ -23,10 +24,6 @@ import { Agent, AgentStatus } from '../../../../../ingest_manager/common/types/m import { findAllUnenrolledAgentIds } from './support/unenroll'; import { findAgentIDsByStatus } from './support/agent_status'; -interface HitSource { - _source: HostMetadata; -} - interface MetadataRequestContext { agentService: AgentService; logger: Logger; @@ -127,7 +124,7 @@ export function registerEndpointRoutes(router: IRouter, endpointAppContext: Endp const queryParams = await kibanaRequestToMetadataListESQuery( req, endpointAppContext, - metadataIndexPattern, + metadataCurrentIndexPattern, { unenrolledAgentIds: unenrolledAgentIds.concat(IGNORED_ELASTIC_AGENT_IDS), statusAgentIDs: statusIDs, @@ -137,7 +134,7 @@ export function registerEndpointRoutes(router: IRouter, endpointAppContext: Endp const response = (await context.core.elasticsearch.legacy.client.callAsCurrentUser( 'search', queryParams - )) as SearchResponse; + )) as SearchResponse; return res.ok({ body: await mapToHostResultList(queryParams, response, metadataRequestContext), @@ -193,17 +190,17 @@ export async function getHostData( metadataRequestContext: MetadataRequestContext, id: string ): Promise { - const query = getESQueryHostMetadataByID(id, metadataIndexPattern); + const query = getESQueryHostMetadataByID(id, metadataCurrentIndexPattern); const response = (await metadataRequestContext.requestHandlerContext.core.elasticsearch.legacy.client.callAsCurrentUser( 'search', query - )) as SearchResponse; + )) as SearchResponse; if (response.hits.hits.length === 0) { return undefined; } - const hostMetadata: HostMetadata = response.hits.hits[0]._source; + const hostMetadata: HostMetadata = response.hits.hits[0]._source.HostDetails; const agent = await findAgent(metadataRequestContext, hostMetadata); if (agent && !agent.active) { @@ -241,19 +238,19 @@ async function findAgent( async function mapToHostResultList( // eslint-disable-next-line @typescript-eslint/no-explicit-any queryParams: Record, - searchResponse: SearchResponse, + searchResponse: SearchResponse, metadataRequestContext: MetadataRequestContext ): Promise { - const totalNumberOfHosts = searchResponse?.aggregations?.total?.value || 0; + const totalNumberOfHosts = + ((searchResponse.hits?.total as unknown) as { value: number; relation: string }).value || 0; if (searchResponse.hits.hits.length > 0) { return { request_page_size: queryParams.size, request_page_index: queryParams.from, hosts: await Promise.all( - searchResponse.hits.hits - .map((response) => response.inner_hits.most_recent.hits.hits) - .flatMap((data) => data as HitSource) - .map(async (entry) => enrichHostMetadata(entry._source, metadataRequestContext)) + searchResponse.hits.hits.map(async (entry) => + enrichHostMetadata(entry._source.HostDetails, metadataRequestContext) + ) ), total: totalNumberOfHosts, }; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts index 29624b35d5c9..f784941f3539 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts @@ -23,6 +23,7 @@ import { import { HostInfo, HostMetadata, + HostMetadataDetails, HostResultList, HostStatus, } from '../../../../common/endpoint/types'; @@ -141,7 +142,7 @@ describe('test endpoint route', () => { bool: { must_not: { terms: { - 'elastic.agent.id': [ + 'HostDetails.elastic.agent.id': [ '00000000-0000-0000-0000-000000000000', '11111111-1111-1111-1111-111111111111', ], @@ -197,7 +198,7 @@ describe('test endpoint route', () => { bool: { must_not: { terms: { - 'elastic.agent.id': [ + 'HostDetails.elastic.agent.id': [ '00000000-0000-0000-0000-000000000000', '11111111-1111-1111-1111-111111111111', ], @@ -442,7 +443,7 @@ describe('Filters Schema Test', () => { }); }); -function createSearchResponse(hostMetadata?: HostMetadata): SearchResponse { +function createSearchResponse(hostMetadata?: HostMetadata): SearchResponse { return ({ took: 15, timed_out: false, @@ -454,7 +455,7 @@ function createSearchResponse(hostMetadata?: HostMetadata): SearchResponse; + } as unknown) as SearchResponse; } diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts index e9eb7093a763..84da4a096082 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts @@ -7,7 +7,7 @@ import { httpServerMock, loggingSystemMock } from '../../../../../../../src/core import { kibanaRequestToMetadataListESQuery, getESQueryHostMetadataByID } from './query_builders'; import { EndpointAppContextService } from '../../endpoint_app_context_services'; import { createMockConfig } from '../../../lib/detection_engine/routes/__mocks__'; -import { metadataIndexPattern } from '../../../../common/endpoint/constants'; +import { metadataCurrentIndexPattern } from '../../../../common/endpoint/constants'; describe('query builder', () => { describe('MetadataListESQuery', () => { @@ -22,31 +22,16 @@ describe('query builder', () => { service: new EndpointAppContextService(), config: () => Promise.resolve(createMockConfig()), }, - metadataIndexPattern + metadataCurrentIndexPattern ); expect(query).toEqual({ body: { query: { match_all: {}, }, - collapse: { - field: 'host.id', - inner_hits: { - name: 'most_recent', - size: 1, - sort: [{ 'event.created': 'desc' }], - }, - }, - aggs: { - total: { - cardinality: { - field: 'host.id', - }, - }, - }, sort: [ { - 'event.created': { + 'HostDetails.event.created': { order: 'desc', }, }, @@ -54,7 +39,7 @@ describe('query builder', () => { }, from: 0, size: 10, - index: metadataIndexPattern, + index: metadataCurrentIndexPattern, // eslint-disable-next-line @typescript-eslint/no-explicit-any } as Record); }); @@ -74,7 +59,7 @@ describe('query builder', () => { service: new EndpointAppContextService(), config: () => Promise.resolve(createMockConfig()), }, - metadataIndexPattern, + metadataCurrentIndexPattern, { unenrolledAgentIds: [unenrolledElasticAgentId], } @@ -86,29 +71,14 @@ describe('query builder', () => { bool: { must_not: { terms: { - 'elastic.agent.id': [unenrolledElasticAgentId], + 'HostDetails.elastic.agent.id': [unenrolledElasticAgentId], }, }, }, }, - collapse: { - field: 'host.id', - inner_hits: { - name: 'most_recent', - size: 1, - sort: [{ 'event.created': 'desc' }], - }, - }, - aggs: { - total: { - cardinality: { - field: 'host.id', - }, - }, - }, sort: [ { - 'event.created': { + 'HostDetails.event.created': { order: 'desc', }, }, @@ -116,7 +86,7 @@ describe('query builder', () => { }, from: 0, size: 10, - index: metadataIndexPattern, + index: metadataCurrentIndexPattern, // eslint-disable-next-line @typescript-eslint/no-explicit-any } as Record); } @@ -127,7 +97,7 @@ describe('query builder', () => { it('test default query params for all endpoints metadata when body filter is provided', async () => { const mockRequest = httpServerMock.createKibanaRequest({ body: { - filters: { kql: 'not host.ip:10.140.73.246' }, + filters: { kql: 'not HostDetails.host.ip:10.140.73.246' }, }, }); const query = await kibanaRequestToMetadataListESQuery( @@ -137,7 +107,7 @@ describe('query builder', () => { service: new EndpointAppContextService(), config: () => Promise.resolve(createMockConfig()), }, - metadataIndexPattern + metadataCurrentIndexPattern ); expect(query).toEqual({ @@ -152,7 +122,7 @@ describe('query builder', () => { should: [ { match: { - 'host.ip': '10.140.73.246', + 'HostDetails.host.ip': '10.140.73.246', }, }, ], @@ -164,24 +134,9 @@ describe('query builder', () => { ], }, }, - collapse: { - field: 'host.id', - inner_hits: { - name: 'most_recent', - size: 1, - sort: [{ 'event.created': 'desc' }], - }, - }, - aggs: { - total: { - cardinality: { - field: 'host.id', - }, - }, - }, sort: [ { - 'event.created': { + 'HostDetails.event.created': { order: 'desc', }, }, @@ -189,7 +144,7 @@ describe('query builder', () => { }, from: 0, size: 10, - index: metadataIndexPattern, + index: metadataCurrentIndexPattern, // eslint-disable-next-line @typescript-eslint/no-explicit-any } as Record); }); @@ -201,7 +156,7 @@ describe('query builder', () => { const unenrolledElasticAgentId = '1fdca33f-799f-49f4-939c-ea4383c77672'; const mockRequest = httpServerMock.createKibanaRequest({ body: { - filters: { kql: 'not host.ip:10.140.73.246' }, + filters: { kql: 'not HostDetails.host.ip:10.140.73.246' }, }, }); const query = await kibanaRequestToMetadataListESQuery( @@ -211,7 +166,7 @@ describe('query builder', () => { service: new EndpointAppContextService(), config: () => Promise.resolve(createMockConfig()), }, - metadataIndexPattern, + metadataCurrentIndexPattern, { unenrolledAgentIds: [unenrolledElasticAgentId], } @@ -226,7 +181,7 @@ describe('query builder', () => { bool: { must_not: { terms: { - 'elastic.agent.id': [unenrolledElasticAgentId], + 'HostDetails.elastic.agent.id': [unenrolledElasticAgentId], }, }, }, @@ -238,7 +193,7 @@ describe('query builder', () => { should: [ { match: { - 'host.ip': '10.140.73.246', + 'HostDetails.host.ip': '10.140.73.246', }, }, ], @@ -250,24 +205,9 @@ describe('query builder', () => { ], }, }, - collapse: { - field: 'host.id', - inner_hits: { - name: 'most_recent', - size: 1, - sort: [{ 'event.created': 'desc' }], - }, - }, - aggs: { - total: { - cardinality: { - field: 'host.id', - }, - }, - }, sort: [ { - 'event.created': { + 'HostDetails.event.created': { order: 'desc', }, }, @@ -275,7 +215,7 @@ describe('query builder', () => { }, from: 0, size: 10, - index: metadataIndexPattern, + index: metadataCurrentIndexPattern, // eslint-disable-next-line @typescript-eslint/no-explicit-any } as Record); } @@ -285,15 +225,15 @@ describe('query builder', () => { describe('MetadataGetQuery', () => { it('searches for the correct ID', () => { const mockID = 'AABBCCDD-0011-2233-AA44-DEADBEEF8899'; - const query = getESQueryHostMetadataByID(mockID, metadataIndexPattern); + const query = getESQueryHostMetadataByID(mockID, metadataCurrentIndexPattern); expect(query).toEqual({ body: { - query: { match: { 'host.id': mockID } }, - sort: [{ 'event.created': { order: 'desc' } }], + query: { match: { 'HostDetails.host.id': mockID } }, + sort: [{ 'HostDetails.event.created': { order: 'desc' } }], size: 1, }, - index: metadataIndexPattern, + index: metadataCurrentIndexPattern, }); }); }); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.ts index ba9be96201db..9002d328efbe 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.ts @@ -28,24 +28,9 @@ export async function kibanaRequestToMetadataListESQuery( queryBuilderOptions?.unenrolledAgentIds!, queryBuilderOptions?.statusAgentIDs! ), - collapse: { - field: 'host.id', - inner_hits: { - name: 'most_recent', - size: 1, - sort: [{ 'event.created': 'desc' }], - }, - }, - aggs: { - total: { - cardinality: { - field: 'host.id', - }, - }, - }, sort: [ { - 'event.created': { + 'HostDetails.event.created': { order: 'desc', }, }, @@ -90,7 +75,7 @@ function buildQueryBody( ? { must_not: { terms: { - 'elastic.agent.id': unerolledAgentIds, + 'HostDetails.elastic.agent.id': unerolledAgentIds, }, }, } @@ -99,7 +84,7 @@ function buildQueryBody( ? { must: { terms: { - 'elastic.agent.id': statusAgentIDs, + 'HostDetails.elastic.agent.id': statusAgentIDs, }, }, } @@ -137,12 +122,12 @@ export function getESQueryHostMetadataByID(hostID: string, index: string) { body: { query: { match: { - 'host.id': hostID, + 'HostDetails.host.id': hostID, }, }, sort: [ { - 'event.created': { + 'HostDetails.event.created': { order: 'desc', }, }, diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts index a3e6f54f3eee..ec4d1efb81b1 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/handlers.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { RequestHandler } from 'kibana/server'; +import { RequestHandler, RequestHandlerContext } from 'kibana/server'; import { GetTrustedAppsListRequest, GetTrustedListAppsResponse, @@ -14,6 +14,17 @@ import { EndpointAppContext } from '../../types'; import { exceptionItemToTrustedAppItem, newTrustedAppItemToExceptionItem } from './utils'; import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common/constants'; import { DeleteTrustedAppsRequestParams } from './types'; +import { ExceptionListClient } from '../../../../../lists/server'; + +const exceptionListClientFromContext = (context: RequestHandlerContext): ExceptionListClient => { + const exceptionLists = context.lists?.getExceptionListClient(); + + if (!exceptionLists) { + throw new Error('Exception List client not found'); + } + + return exceptionLists; +}; export const getTrustedAppsDeleteRouteHandler = ( endpointAppContext: EndpointAppContext @@ -21,9 +32,8 @@ export const getTrustedAppsDeleteRouteHandler = ( const logger = endpointAppContext.logFactory.get('trusted_apps'); return async (context, req, res) => { - const exceptionsListService = endpointAppContext.service.getExceptionsList(); - try { + const exceptionsListService = exceptionListClientFromContext(context); const { id } = req.params; const response = await exceptionsListService.deleteExceptionListItem({ id, @@ -49,10 +59,10 @@ export const getTrustedAppsListRouteHandler = ( const logger = endpointAppContext.logFactory.get('trusted_apps'); return async (context, req, res) => { - const exceptionsListService = endpointAppContext.service.getExceptionsList(); const { page, per_page: perPage } = req.query; try { + const exceptionsListService = exceptionListClientFromContext(context); // Ensure list is created if it does not exist await exceptionsListService.createTrustedAppsList(); const results = await exceptionsListService.findExceptionListItem({ @@ -83,11 +93,11 @@ export const getTrustedAppsCreateRouteHandler = ( ): RequestHandler => { const logger = endpointAppContext.logFactory.get('trusted_apps'); - return async (constext, req, res) => { - const exceptionsListService = endpointAppContext.service.getExceptionsList(); + return async (context, req, res) => { const newTrustedApp = req.body; try { + const exceptionsListService = exceptionListClientFromContext(context); // Ensure list is created if it does not exist await exceptionsListService.createTrustedAppsList(); diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts index 2325036ef40a..eeee2d99bf26 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/trusted_apps.test.ts @@ -24,15 +24,23 @@ import { import { xpackMocks } from '../../../../../../mocks'; import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common/constants'; import { EndpointAppContext } from '../../types'; -import { ExceptionListClient } from '../../../../../lists/server'; -import { getExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; +import { ExceptionListClient, ListClient } from '../../../../../lists/server'; +import { listMock } from '../../../../../lists/server/mocks'; import { ExceptionListItemSchema } from '../../../../../lists/common/schemas/response'; import { DeleteTrustedAppsRequestParams } from './types'; +import { getExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; + +type RequestHandlerContextWithLists = ReturnType & { + lists?: { + getListClient: () => jest.Mocked; + getExceptionListClient: () => jest.Mocked; + }; +}; describe('when invoking endpoint trusted apps route handlers', () => { let routerMock: jest.Mocked; let endpointAppContextService: EndpointAppContextService; - let context: ReturnType; + let context: RequestHandlerContextWithLists; let response: ReturnType; let exceptionsListClient: jest.Mocked; let endpointAppContext: EndpointAppContext; @@ -41,7 +49,7 @@ describe('when invoking endpoint trusted apps route handlers', () => { routerMock = httpServiceMock.createRouter(); endpointAppContextService = new EndpointAppContextService(); const startContract = createMockEndpointAppContextServiceStartContract(); - exceptionsListClient = startContract.exceptionsListService as jest.Mocked; + exceptionsListClient = listMock.getExceptionListClient() as jest.Mocked; endpointAppContextService.start(startContract); endpointAppContext = { ...createMockEndpointAppContext(), @@ -50,7 +58,13 @@ describe('when invoking endpoint trusted apps route handlers', () => { registerTrustedAppsRoutes(routerMock, endpointAppContext); // For use in individual API calls - context = xpackMocks.createRequestHandlerContext(); + context = { + ...xpackMocks.createRequestHandlerContext(), + lists: { + getListClient: jest.fn(), + getExceptionListClient: jest.fn().mockReturnValue(exceptionsListClient), + }, + }; response = httpServerMock.createResponseFactory(); }); @@ -74,6 +88,12 @@ describe('when invoking endpoint trusted apps route handlers', () => { )!; }); + it('should use ExceptionListClient from route handler context', async () => { + const request = createListRequest(); + await routeHandler(context, request, response); + expect(context.lists?.getExceptionListClient).toHaveBeenCalled(); + }); + it('should create the Trusted Apps List first', async () => { const request = createListRequest(); await routeHandler(context, request, response); @@ -155,6 +175,12 @@ describe('when invoking endpoint trusted apps route handlers', () => { }); }); + it('should use ExceptionListClient from route handler context', async () => { + const request = createPostRequest(); + await routeHandler(context, request, response); + expect(context.lists?.getExceptionListClient).toHaveBeenCalled(); + }); + it('should create trusted app list first', async () => { const request = createPostRequest(); await routeHandler(context, request, response); @@ -238,6 +264,11 @@ describe('when invoking endpoint trusted apps route handlers', () => { }); }); + it('should use ExceptionListClient from route handler context', async () => { + await routeHandler(context, request, response); + expect(context.lists?.getExceptionListClient).toHaveBeenCalled(); + }); + it('should return 200 on successful delete', async () => { await routeHandler(context, request, response); expect(exceptionsListClient.deleteExceptionListItem).toHaveBeenCalledWith({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signals_mapping.json b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signals_mapping.json index 7d80a319e9e5..cfce01991007 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signals_mapping.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/signals_mapping.json @@ -22,11 +22,33 @@ } } }, + "parents": { + "properties": { + "rule": { + "type": "keyword" + }, + "index": { + "type": "keyword" + }, + "id": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "depth": { + "type": "long" + } + } + }, "ancestors": { "properties": { "rule": { "type": "keyword" }, + "index": { + "type": "keyword" + }, "id": { "type": "keyword" }, @@ -299,6 +321,9 @@ }, "threshold_count": { "type": "float" + }, + "depth": { + "type": "integer" } } } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/README.md b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/README.md index 2310ba979da2..7cf7d11e4c1f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/README.md +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/README.md @@ -22,7 +22,7 @@ which will write a single signal document into the signals index by searching fo signal_on_signal_depth_1.json ``` -which has this key part of its query: `"query": "signal.parent.depth: 1 and _id: *"` which will only create signals +which has this key part of its query: `"query": "signal.depth: 1 and _id: *"` which will only create signals from all signals that point directly to an event (signal -> event). Then a second rule called @@ -34,7 +34,7 @@ signal_on_signal_depth_2.json which will only create signals from all signals that point directly to another signal (signal -> signal) with this query ```json -"query": "signal.parent.depth: 2 and _id: *" +"query": "signal.depth: 2 and _id: *" ``` ## Setup @@ -90,38 +90,43 @@ And then you can query against that: GET .siem-signals-default/_search ``` -Check your parent section of the signal and you will see something like this: +Check your `signal` section of the signal and you will see something like this: ```json -"parent" : { - "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", - "id" : "o8G7vm8BvLT8jmu5B1-M", - "type" : "event", - "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 -}, -"ancestors" : [ +"parents" : [ { - "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 } -] +], +"ancestors" : [ + { + "id" : "o8G7vm8BvLT8jmu5B1-M", + "type" : "event", + "index" : "filebeat-8.0.0-2019.12.18-000001", + "depth" : 0 + }, +], +"depth": 1, +"rule": { + "id": "74e0dd0c-4609-416f-b65e-90f8b2564612" +} ``` -The parent and ancestors structure is defined as: +The parents structure is defined as: ``` -rule -> The id of the rule. You can view the rule by ./get_rule_by_rule_id.sh ded57b36-9c4e-4ee4-805d-be4e92033e41 +rule -> The id of the rule, if the parent was generated by a rule. You can view the rule by ./get_rule_by_rule_id.sh ded57b36-9c4e-4ee4-805d-be4e92033e41 id -> The original _id of the document type -> The type of the document, it will be either event or signal index -> The original location of the index -depth -> The depth of this signal. It will be at least 1 to indicate it is a signal generated from a event. Otherwise 2 or more to indicate a signal on signal and what depth we are at -ancestors -> An array tracking all of the parents of this particular signal. As depth increases this will too. +depth -> The depth of the parent event/signal. It will be 0 if the parent is an event, or 1+ if the parent is another signal. ``` +The ancestors structure has the same fields as parents, but is an array of all ancestors (parents, grandparents, etc) of the signal. + This is indicating that you have a single parent of an event from the signal (signal -> event) and this document has a single ancestor of that event. Each 30 seconds that goes it will use de-duplication technique to ensure that this signal is not re-inserted. If after each 30 seconds you DO SEE multiple signals then the bug is a de-duplication bug and a critical bug. If you ever see a duplicate rule in the @@ -138,55 +143,64 @@ running in the system which are generating signals on top of signals. After 30 s documents in the signals index. The first signal is our original (signal -> event) document with a rule id: ```json -"parent" : { - "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", - "id" : "o8G7vm8BvLT8jmu5B1-M", - "type" : "event", - "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 -}, +"parents" : [ + { + "id" : "o8G7vm8BvLT8jmu5B1-M", + "type" : "event", + "index" : "filebeat-8.0.0-2019.12.18-000001", + "depth" : 0 + } +], "ancestors" : [ { - "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 } -] +], +"depth": 1, +"rule": { + "id": "74e0dd0c-4609-416f-b65e-90f8b2564612" +} ``` and the second document is a signal on top of a signal like so: ```json -"parent" : { - "rule" : "1d3b3735-66ef-4e53-b7f5-4340026cc40c", - "id" : "4cc69c1cbecdd2ace4075fd1d8a5c28e7d46e4bf31aecc8d2da39252c50c96b4", - "type" : "signal", - "index" : ".siem-signals-default-000001", - "depth" : 2 -}, -"ancestors" : [ +"parents" : [ { "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", + "id" : "4cc69c1cbecdd2ace4075fd1d8a5c28e7d46e4bf31aecc8d2da39252c50c96b4", + "type" : "signal", + "index" : ".siem-signals-default-000001", + "depth" : 1 + } +] +"ancestors" : [ + { "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 }, { - "rule" : "1d3b3735-66ef-4e53-b7f5-4340026cc40c", + "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", "id" : "4cc69c1cbecdd2ace4075fd1d8a5c28e7d46e4bf31aecc8d2da39252c50c96b4", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 2 + "depth" : 1 } -] +], +"depth": 2, +"rule": { + "id": "1d3b3735-66ef-4e53-b7f5-4340026cc40c" +} ``` Notice that the depth indicates it is at level 2 and its parent is that of a signal. Also notice that the ancestors is an array of size 2 indicating that this signal terminates at an event. Each and every signal ancestors array should terminate at an event and should ONLY contain 1 -event and NEVER 2 or more events. After 30+ seconds you should NOT see any new documents being created and you should be stable +event and NEVER 2 or more events for KQL query based rules. EQL query based rules that use sequences may have multiple parents at the same level. After 30+ seconds you should NOT see any new documents being created and you should be stable at 2. Otherwise we have AND/OR a de-duplication issue, signal on signal issue. Now, post this same rule a second time as a second instance which is going to run against these two documents. @@ -212,79 +226,93 @@ The expected behavior is that eventually you will get 3 total documents but not The original event rule 74e0dd0c-4609-416f-b65e-90f8b2564612 (event -> signal) ```json -"parent" : { - "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", - "id" : "o8G7vm8BvLT8jmu5B1-M", - "type" : "event", - "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 -}, +"parents" : [ + { + "id" : "o8G7vm8BvLT8jmu5B1-M", + "type" : "event", + "index" : "filebeat-8.0.0-2019.12.18-000001", + "depth" : 0 + } +], "ancestors" : [ { - "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 } -] +], +"depth": 1, +"rule": { + "id": "74e0dd0c-4609-416f-b65e-90f8b2564612" +} ``` The first signal to signal rule 1d3b3735-66ef-4e53-b7f5-4340026cc40c (signal -> event) ```json -"parent" : { - "rule" : "1d3b3735-66ef-4e53-b7f5-4340026cc40c", - "id" : "4cc69c1cbecdd2ace4075fd1d8a5c28e7d46e4bf31aecc8d2da39252c50c96b4", - "type" : "signal", - "index" : ".siem-signals-default-000001", - "depth" : 2 -}, -"ancestors" : [ +"parents" : [ { "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", + "id" : "4cc69c1cbecdd2ace4075fd1d8a5c28e7d46e4bf31aecc8d2da39252c50c96b4", + "type" : "signal", + "index" : ".siem-signals-default-000001", + "depth" : 1 + } +] +"ancestors" : [ + { "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 }, { - "rule" : "1d3b3735-66ef-4e53-b7f5-4340026cc40c", + "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", "id" : "4cc69c1cbecdd2ace4075fd1d8a5c28e7d46e4bf31aecc8d2da39252c50c96b4", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 2 + "depth" : 1 } -] +], +"depth": 2, +"rule": { + "id": "1d3b3735-66ef-4e53-b7f5-4340026cc40c" +} ``` Then our second signal to signal rule c93ddb57-e7e9-4973-9886-72ddefb4d22e (signal -> event) which finds the same thing as the first signal to signal ```json -"parent" : { - "rule" : "c93ddb57-e7e9-4973-9886-72ddefb4d22e", - "id" : "4cc69c1cbecdd2ace4075fd1d8a5c28e7d46e4bf31aecc8d2da39252c50c96b4", - "type" : "signal", - "index" : ".siem-signals-default-000001", - "depth" : 2 -}, -"ancestors" : [ +"parents" : [ { "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", + "id" : "4cc69c1cbecdd2ace4075fd1d8a5c28e7d46e4bf31aecc8d2da39252c50c96b4", + "type" : "signal", + "index" : ".siem-signals-default-000001", + "depth" : 1 + } +], +"ancestors" : [ + { "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 }, { - "rule" : "c93ddb57-e7e9-4973-9886-72ddefb4d22e", + "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", "id" : "4cc69c1cbecdd2ace4075fd1d8a5c28e7d46e4bf31aecc8d2da39252c50c96b4", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 2 + "depth" : 1 } -] +], +"depth": 2, +"rule": { + "id": "c93ddb57-e7e9-4973-9886-72ddefb4d22e" +} ``` We should be able to post this depth level as many times as we want and get only 1 new document each time. If we decide though to @@ -298,69 +326,79 @@ The expectation is that a document for each of the previous depth 1 documents wo depth 1 rules running then the signals at depth 2 will produce two new ones and those two will look like so: ```json -"parent" : { - "rule" : "a1f7b520-5bfd-451d-af59-428f60753fee", - "id" : "365236ce5e77770508152403b4e16613f407ae4b1a135a450dcfec427f2a3231", - "type" : "signal", - "index" : ".siem-signals-default-000001", - "depth" : 3 -}, +"parents" : [ + { + "rule" : "1d3b3735-66ef-4e53-b7f5-4340026cc40c", + "id" : "365236ce5e77770508152403b4e16613f407ae4b1a135a450dcfec427f2a3231", + "type" : "signal", + "index" : ".siem-signals-default-000001", + "depth" : 2 + } +], "ancestors" : [ { - "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 }, { - "rule" : "1d3b3735-66ef-4e53-b7f5-4340026cc40c", + "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", "id" : "4cc69c1cbecdd2ace4075fd1d8a5c28e7d46e4bf31aecc8d2da39252c50c96b4", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 2 + "depth" : 1 }, { - "rule" : "a1f7b520-5bfd-451d-af59-428f60753fee", + "rule" : "1d3b3735-66ef-4e53-b7f5-4340026cc40c", "id" : "365236ce5e77770508152403b4e16613f407ae4b1a135a450dcfec427f2a3231", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 3 + "depth" : 2 } -] +], +"depth": 3, +"rule": { + "id": "a1f7b520-5bfd-451d-af59-428f60753fee" +} ``` ```json -"parent" : { - "rule" : "a1f7b520-5bfd-451d-af59-428f60753fee", - "id" : "e8b1f1adb40fd642fa524dea89ef94232e67b05e99fb0b2683f1e47e90b759fb", - "type" : "signal", - "index" : ".siem-signals-default-000001", - "depth" : 3 -}, +"parents" : [ + { + "rule" : "c93ddb57-e7e9-4973-9886-72ddefb4d22e", + "id" : "e8b1f1adb40fd642fa524dea89ef94232e67b05e99fb0b2683f1e47e90b759fb", + "type" : "signal", + "index" : ".siem-signals-default-000001", + "depth" : 2 + } +], "ancestors" : [ { - "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 }, { - "rule" : "c93ddb57-e7e9-4973-9886-72ddefb4d22e", + "rule" : "74e0dd0c-4609-416f-b65e-90f8b2564612", "id" : "4cc69c1cbecdd2ace4075fd1d8a5c28e7d46e4bf31aecc8d2da39252c50c96b4", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 2 + "depth" : 1 }, { - "rule" : "a1f7b520-5bfd-451d-af59-428f60753fee", + "rule" : "c93ddb57-e7e9-4973-9886-72ddefb4d22e", "id" : "e8b1f1adb40fd642fa524dea89ef94232e67b05e99fb0b2683f1e47e90b759fb", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 3 + "depth" : 2 } -] +], +"depth": 3, +"rule": { + "id": "a1f7b520-5bfd-451d-af59-428f60753fee" +} ``` The total number of documents should be 5 at this point. If you were to post this same rule a second time to get a second instance diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/query_single_id.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/query_single_id.json index dc05c656d7cf..305aa3499262 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/query_single_id.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/query_single_id.json @@ -7,6 +7,6 @@ "from": "now-1d", "interval": "30s", "to": "now", - "query": "_id: o8G7vm8BvLT8jmu5B1-M", + "query": "event.id: 08cde4aa-d249-4e6b-8300-06f3d56c7fe7", "enabled": true } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/signal_on_signal_depth_1.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/signal_on_signal_depth_1.json index fb13413a0279..c9132ddb0a59 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/signal_on_signal_depth_1.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/signal_on_signal_depth_1.json @@ -7,7 +7,7 @@ "from": "now-1d", "interval": "30s", "to": "now", - "query": "signal.parent.depth: 1 and _id: *", + "query": "signal.depth: 1 and _id: *", "enabled": true, - "index": ".siem-signals-default" + "index": [".siem-signals-default"] } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/signal_on_signal_depth_2.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/signal_on_signal_depth_2.json index c1b7594653ec..d1a274979268 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/signal_on_signal_depth_2.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/depth_test/signal_on_signal_depth_2.json @@ -7,7 +7,7 @@ "from": "now-1d", "interval": "30s", "to": "now", - "query": "signal.parent.depth: 2 and _id: *", + "query": "signal.depth: 2 and _id: *", "enabled": true, - "index": ".siem-signals-default" + "index": [".siem-signals-default"] } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/halting_test/README.md b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/halting_test/README.md index b1a83f531777..01b21bf762e4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/halting_test/README.md +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/rules/test_cases/signals_on_signals/halting_test/README.md @@ -69,38 +69,43 @@ And then you can query against that: GET .siem-signals-default/_search ``` -Check your parent section of the signal and you will see something like this: +Check your `signal` section of the signal and you will see something like this: ```json -"parent" : { - "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", - "id" : "o8G7vm8BvLT8jmu5B1-M", - "type" : "event", - "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 -}, -"ancestors" : [ +"parents" : [ { - "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 } -] +], +"ancestors" : [ + { + "id" : "o8G7vm8BvLT8jmu5B1-M", + "type" : "event", + "index" : "filebeat-8.0.0-2019.12.18-000001", + "depth" : 0 + }, +], +"depth": 1, +"rule": { + "id": "ded57b36-9c4e-4ee4-805d-be4e92033e41" +} ``` -The parent and ancestors structure is defined as: +The parents structure is defined as: ``` -rule -> The id of the rule. You can view the rule by ./get_rule_by_rule_id.sh ded57b36-9c4e-4ee4-805d-be4e92033e41 +rule -> The id of the rule, if the parent was generated by a rule. You can view the rule by ./get_rule_by_rule_id.sh ded57b36-9c4e-4ee4-805d-be4e92033e41 id -> The original _id of the document type -> The type of the document, it will be either event or signal index -> The original location of the index -depth -> The depth of this signal. It will be at least 1 to indicate it is a signal generated from a event. Otherwise 2 or more to indicate a signal on signal and what depth we are at -ancestors -> An array tracking all of the parents of this particular signal. As depth increases this will too. +depth -> The depth of the parent event/signal. It will be 0 if the parent is an event, or 1+ if the parent is another signal. ``` +The ancestors structure has the same fields as parents, but is an array of all ancestors (parents, grandparents, etc) of the signal. + This is indicating that you have a single parent of an event from the signal (signal -> event) and this document has a single ancestor of that event. Each 30 seconds that goes it will use de-duplication technique to ensure that this signal is not re-inserted. If after each 30 seconds you DO SEE multiple signals then the bug is a de-duplication bug and a critical bug. If you ever see a duplicate rule in the @@ -119,22 +124,26 @@ documents in the signals index. The first signal is our original (signal -> even (signal -> event) ```json -"parent" : { - "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", - "id" : "o8G7vm8BvLT8jmu5B1-M", - "type" : "event", - "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 -}, -"ancestors" : [ +"parents" : [ { - "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 } -] +], +"ancestors" : [ + { + "id" : "o8G7vm8BvLT8jmu5B1-M", + "type" : "event", + "index" : "filebeat-8.0.0-2019.12.18-000001", + "depth" : 0 + }, +], +"depth": 1, +"rule": { + "id": "ded57b36-9c4e-4ee4-805d-be4e92033e41" +} ``` and the second document is a signal on top of a signal like so: @@ -143,28 +152,31 @@ and the second document is a signal on top of a signal like so: ```json "parent" : { - "rule" : "161fa5b8-0b96-4985-b066-0d99b2bcb904", + "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "9d8710925adbf1a9c469621805407e74334dd08ca2c2ea414840fe971a571938", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 2 + "depth" : 1 }, "ancestors" : [ { - "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 }, { - "rule" : "161fa5b8-0b96-4985-b066-0d99b2bcb904", + "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "9d8710925adbf1a9c469621805407e74334dd08ca2c2ea414840fe971a571938", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 2 + "depth" : 1 } -] +], +"depth": 2, +"rule": { + "id": "161fa5b8-0b96-4985-b066-0d99b2bcb904" +} ``` Notice that the depth indicates it is at level 2 and its parent is that of a signal. Also notice that the ancestors is an array of size 2 @@ -195,50 +207,57 @@ The expected behavior is that eventually you will get 5 total documents but not The original event rule ded57b36-9c4e-4ee4-805d-be4e92033e41 (event -> signal) ```json -"parent" : { - "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", - "id" : "o8G7vm8BvLT8jmu5B1-M", - "type" : "event", - "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 -}, -"ancestors" : [ +"parents" : [ { - "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 } -] +], +"ancestors" : [ + { + "id" : "o8G7vm8BvLT8jmu5B1-M", + "type" : "event", + "index" : "filebeat-8.0.0-2019.12.18-000001", + "depth" : 0 + }, +], +"depth": 1, +"rule": { + "id": "ded57b36-9c4e-4ee4-805d-be4e92033e41" +} ``` The first signal to signal rule 161fa5b8-0b96-4985-b066-0d99b2bcb904 (signal -> event) ```json "parent" : { - "rule" : "161fa5b8-0b96-4985-b066-0d99b2bcb904", + "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "9d8710925adbf1a9c469621805407e74334dd08ca2c2ea414840fe971a571938", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 2 + "depth" : 1 }, "ancestors" : [ { - "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 }, { - "rule" : "161fa5b8-0b96-4985-b066-0d99b2bcb904", + "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "9d8710925adbf1a9c469621805407e74334dd08ca2c2ea414840fe971a571938", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 2 + "depth" : 1 } -] +], +"depth": 2, +"rule": { + "id": "161fa5b8-0b96-4985-b066-0d99b2bcb904" +} ``` Then our second signal to signal rule f2b70c4a-4d8f-4db5-9ed7-d3ab0630e406 (signal -> event) which finds the same thing as the first @@ -246,28 +265,31 @@ signal to signal ```json "parent" : { - "rule" : "f2b70c4a-4d8f-4db5-9ed7-d3ab0630e406", + "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "9d8710925adbf1a9c469621805407e74334dd08ca2c2ea414840fe971a571938", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 2 + "depth" : 1 }, "ancestors" : [ { - "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 }, { - "rule" : "f2b70c4a-4d8f-4db5-9ed7-d3ab0630e406", + "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "9d8710925adbf1a9c469621805407e74334dd08ca2c2ea414840fe971a571938", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 2 + "depth" : 1 } -] +], +"depth": 2, +"rule": { + "id": "f2b70c4a-4d8f-4db5-9ed7-d3ab0630e406" +} ``` But then f2b70c4a-4d8f-4db5-9ed7-d3ab0630e406 also finds the first signal to signal rule from 161fa5b8-0b96-4985-b066-0d99b2bcb904 @@ -275,35 +297,38 @@ and writes that document out with a depth of 3. (signal -> signal -> event) ```json "parent" : { - "rule" : "f2b70c4a-4d8f-4db5-9ed7-d3ab0630e406", + "rule" : "161fa5b8-0b96-4985-b066-0d99b2bcb904", "id" : "c627e5e2576f1b10952c6c57249947e89b6153b763a59fb9e391d0b56be8e7fe", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 3 + "depth" : 2 }, "ancestors" : [ { - "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 }, { - "rule" : "161fa5b8-0b96-4985-b066-0d99b2bcb904", + "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "9d8710925adbf1a9c469621805407e74334dd08ca2c2ea414840fe971a571938", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 2 + "depth" : 1 }, { - "rule" : "f2b70c4a-4d8f-4db5-9ed7-d3ab0630e406", + "rule" : "161fa5b8-0b96-4985-b066-0d99b2bcb904", "id" : "c627e5e2576f1b10952c6c57249947e89b6153b763a59fb9e391d0b56be8e7fe", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 3 + "depth" : 2 } -] +], +"depth": 3, +"rule": { + "id": "f2b70c4a-4d8f-4db5-9ed7-d3ab0630e406" +} ``` Since it wrote that document, the first signal to signal 161fa5b8-0b96-4985-b066-0d99b2bcb904 writes out it found this newly created signal @@ -311,35 +336,38 @@ Since it wrote that document, the first signal to signal 161fa5b8-0b96-4985-b066 ```json "parent" : { - "rule" : "161fa5b8-0b96-4985-b066-0d99b2bcb904", + "rule" : "f2b70c4a-4d8f-4db5-9ed7-d3ab0630e406", "id" : "efbe514e8d806a5ef3da7658cfa73961e25befefc84f622e963b45dcac798868", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 3 + "depth" : 2 }, "ancestors" : [ { - "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "o8G7vm8BvLT8jmu5B1-M", "type" : "event", "index" : "filebeat-8.0.0-2019.12.18-000001", - "depth" : 1 + "depth" : 0 }, { - "rule" : "f2b70c4a-4d8f-4db5-9ed7-d3ab0630e406", + "rule" : "ded57b36-9c4e-4ee4-805d-be4e92033e41", "id" : "9d8710925adbf1a9c469621805407e74334dd08ca2c2ea414840fe971a571938", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 2 + "depth" : 1 }, { - "rule" : "161fa5b8-0b96-4985-b066-0d99b2bcb904", + "rule" : "f2b70c4a-4d8f-4db5-9ed7-d3ab0630e406", "id" : "efbe514e8d806a5ef3da7658cfa73961e25befefc84f622e963b45dcac798868", "type" : "signal", "index" : ".siem-signals-default-000001", - "depth" : 3 + "depth" : 2 } -] +], +"depth": 3, +"rule": { + "id": "161fa5b8-0b96-4985-b066-0d99b2bcb904" +} ``` You will be "halted" at this point as the signal ancestry and de-duplication ensures that we do not report twice on signals and that we do not diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts index 95ec753c21fd..9d3eb29be08d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/__mocks__/es_results.ts @@ -149,21 +149,23 @@ export const sampleDocWithAncestors = (): SignalSearchResponse => { delete sampleDoc._source.source; sampleDoc._source.signal = { parent: { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, ancestors: [ { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, ], + rule: { + id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + }, + depth: 1, }; return { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.test.ts index ee83c826371b..967dc5331e46 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.test.ts @@ -48,19 +48,25 @@ describe('buildBulkBody', () => { }, signal: { parent: { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: sampleIdGuid, type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, + parents: [ + { + id: sampleIdGuid, + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + ], ancestors: [ { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: sampleIdGuid, type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, ], original_time: '2020-04-20T21:27:45+0000', @@ -102,6 +108,7 @@ describe('buildBulkBody', () => { updated_at: fakeSignalSourceHit.signal.rule?.updated_at, exceptions_list: getListArrayMock(), }, + depth: 1, }, }; expect(fakeSignalSourceHit).toEqual(expected); @@ -151,19 +158,25 @@ describe('buildBulkBody', () => { module: 'system', }, parent: { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: sampleIdGuid, type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, + parents: [ + { + id: sampleIdGuid, + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + ], ancestors: [ { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: sampleIdGuid, type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, ], original_time: '2020-04-20T21:27:45+0000', @@ -205,6 +218,7 @@ describe('buildBulkBody', () => { threat: [], exceptions_list: getListArrayMock(), }, + depth: 1, }, }; expect(fakeSignalSourceHit).toEqual(expected); @@ -252,19 +266,25 @@ describe('buildBulkBody', () => { module: 'system', }, parent: { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: sampleIdGuid, type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, + parents: [ + { + id: sampleIdGuid, + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + ], ancestors: [ { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: sampleIdGuid, type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, ], original_time: '2020-04-20T21:27:45+0000', @@ -306,6 +326,7 @@ describe('buildBulkBody', () => { throttle: 'no_actions', exceptions_list: getListArrayMock(), }, + depth: 1, }, }; expect(fakeSignalSourceHit).toEqual(expected); @@ -346,19 +367,25 @@ describe('buildBulkBody', () => { kind: 'event', }, parent: { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: sampleIdGuid, type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, + parents: [ + { + id: sampleIdGuid, + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + ], ancestors: [ { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: sampleIdGuid, type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, ], original_time: '2020-04-20T21:27:45+0000', @@ -400,6 +427,7 @@ describe('buildBulkBody', () => { throttle: 'no_actions', exceptions_list: getListArrayMock(), }, + depth: 1, }, }; expect(fakeSignalSourceHit).toEqual(expected); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.ts index 218750ac30a2..7be97e46f91f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_bulk_body.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SignalSourceHit, SignalHit } from './types'; +import { SignalSourceHit, SignalHit, Signal } from './types'; import { buildRule } from './build_rule'; -import { buildSignal } from './build_signal'; +import { additionalSignalFields, buildSignal } from './build_signal'; import { buildEventTypeSignal } from './build_event_type_signal'; import { RuleAlertAction } from '../../../../common/detection_engine/types'; import { RuleTypeParams } from '../types'; @@ -58,7 +58,10 @@ export const buildBulkBody = ({ tags, throttle, }); - const signal = buildSignal(doc, rule); + const signal: Signal = { + ...buildSignal([doc], rule), + ...additionalSignalFields(doc), + }; const event = buildEventTypeSignal(doc); const signalHit: SignalHit = { ...doc._source, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_rule.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_rule.test.ts index 7257e5952ff0..ba815a0b62f0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_rule.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_rule.test.ts @@ -4,10 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import { buildRule } from './build_rule'; +import { buildRule, removeInternalTagsFromRule } from './build_rule'; import { sampleDocNoSortId, sampleRuleAlertParams, sampleRuleGuid } from './__mocks__/es_results'; import { RulesSchema } from '../../../../common/detection_engine/schemas/response/rules_schema'; import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock'; +import { INTERNAL_RULE_ID_KEY, INTERNAL_IMMUTABLE_KEY } from '../../../../common/constants'; +import { getPartialRulesSchemaMock } from '../../../../common/detection_engine/schemas/response/rules_schema.mocks'; describe('buildRule', () => { beforeEach(() => { @@ -208,4 +210,102 @@ describe('buildRule', () => { }; expect(rule).toEqual(expected); }); + + test('it builds a rule and removes internal tags', () => { + const ruleParams = sampleRuleAlertParams(); + const rule = buildRule({ + actions: [], + doc: sampleDocNoSortId(), + ruleParams, + name: 'some-name', + id: sampleRuleGuid, + enabled: false, + createdAt: '2020-01-28T15:58:34.810Z', + updatedAt: '2020-01-28T15:59:14.004Z', + createdBy: 'elastic', + updatedBy: 'elastic', + interval: 'some interval', + tags: [ + 'some fake tag 1', + 'some fake tag 2', + `${INTERNAL_RULE_ID_KEY}:rule-1`, + `${INTERNAL_IMMUTABLE_KEY}:true`, + ], + throttle: 'no_actions', + }); + const expected: Partial = { + actions: [], + author: ['Elastic'], + building_block_type: 'default', + created_by: 'elastic', + description: 'Detecting root and admin users', + enabled: false, + false_positives: [], + from: 'now-6m', + id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + immutable: false, + index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], + interval: 'some interval', + language: 'kuery', + license: 'Elastic License', + max_signals: 10000, + name: 'some-name', + output_index: '.siem-signals', + query: 'user.name: root or user.name: admin', + references: ['http://google.com'], + risk_score: 50, + risk_score_mapping: [], + rule_id: 'rule-1', + severity: 'high', + severity_mapping: [], + tags: ['some fake tag 1', 'some fake tag 2'], + threat: [], + to: 'now', + type: 'query', + note: '', + updated_by: 'elastic', + updated_at: rule.updated_at, + created_at: rule.created_at, + throttle: 'no_actions', + exceptions_list: getListArrayMock(), + version: 1, + }; + expect(rule).toEqual(expected); + }); + + test('it removes internal tags from a typical rule', () => { + const rule = getPartialRulesSchemaMock(); + rule.tags = [ + 'some fake tag 1', + 'some fake tag 2', + `${INTERNAL_RULE_ID_KEY}:rule-1`, + `${INTERNAL_IMMUTABLE_KEY}:true`, + ]; + const noInternals = removeInternalTagsFromRule(rule); + expect(noInternals).toEqual(getPartialRulesSchemaMock()); + }); + + test('it works with an empty array', () => { + const rule = getPartialRulesSchemaMock(); + rule.tags = []; + const noInternals = removeInternalTagsFromRule(rule); + const expected = getPartialRulesSchemaMock(); + expected.tags = []; + expect(noInternals).toEqual(expected); + }); + + test('it works if tags does not exist', () => { + const rule = getPartialRulesSchemaMock(); + delete rule.tags; + const noInternals = removeInternalTagsFromRule(rule); + const expected = getPartialRulesSchemaMock(); + delete expected.tags; + expect(noInternals).toEqual(expected); + }); + + test('it works if tags contains normal values and no internal values', () => { + const rule = getPartialRulesSchemaMock(); + const noInternals = removeInternalTagsFromRule(rule); + expect(noInternals).toEqual(rule); + }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_rule.ts index e02a0154d63c..aacf9b8be31b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_rule.ts @@ -12,6 +12,7 @@ import { buildRiskScoreFromMapping } from './mappings/build_risk_score_from_mapp import { SignalSourceHit } from './types'; import { buildSeverityFromMapping } from './mappings/build_severity_from_mapping'; import { buildRuleNameFromMapping } from './mappings/build_rule_name_from_mapping'; +import { INTERNAL_IDENTIFIER } from '../../../../common/constants'; interface BuildRuleParams { ruleParams: RuleTypeParams; @@ -64,7 +65,7 @@ export const buildRule = ({ const meta = { ...ruleParams.meta, ...riskScoreMeta, ...severityMeta, ...ruleNameMeta }; - return pickBy((value: unknown) => value != null, { + const rule = pickBy((value: unknown) => value != null, { id, rule_id: ruleParams.ruleId ?? '(unknown rule_id)', actions, @@ -111,4 +112,17 @@ export const buildRule = ({ anomaly_threshold: ruleParams.anomalyThreshold, threshold: ruleParams.threshold, }); + return removeInternalTagsFromRule(rule); +}; + +export const removeInternalTagsFromRule = (rule: Partial): Partial => { + if (rule.tags == null) { + return rule; + } else { + const ruleWithoutInternalTags: Partial = { + ...rule, + tags: rule.tags.filter((tag) => !tag.startsWith(INTERNAL_IDENTIFIER)), + }; + return ruleWithoutInternalTags; + } }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_signal.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_signal.test.ts index 6aebf8815659..d684807a0912 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_signal.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_signal.test.ts @@ -5,14 +5,8 @@ */ import { sampleDocNoSortId } from './__mocks__/es_results'; -import { - buildSignal, - buildAncestor, - buildAncestorsSignal, - removeInternalTagsFromRule, -} from './build_signal'; +import { buildSignal, buildParent, buildAncestors, additionalSignalFields } from './build_signal'; import { Signal, Ancestor } from './types'; -import { INTERNAL_RULE_ID_KEY, INTERNAL_IMMUTABLE_KEY } from '../../../../common/constants'; import { getPartialRulesSchemaMock } from '../../../../common/detection_engine/schemas/response/rules_schema.mocks'; describe('buildSignal', () => { @@ -24,22 +18,31 @@ describe('buildSignal', () => { const doc = sampleDocNoSortId('d5e8eb51-a6a0-456d-8a15-4b79bfec3d71'); delete doc._source.event; const rule = getPartialRulesSchemaMock(); - const signal = buildSignal(doc, rule); + const signal = { + ...buildSignal([doc], rule), + ...additionalSignalFields(doc), + }; const expected: Signal = { parent: { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, + parents: [ + { + id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + ], ancestors: [ { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, ], original_time: '2020-04-20T21:27:45+0000', @@ -71,6 +74,7 @@ describe('buildSignal', () => { updated_at: signal.rule.updated_at, created_at: signal.rule.created_at, }, + depth: 1, }; expect(signal).toEqual(expected); }); @@ -84,94 +88,31 @@ describe('buildSignal', () => { module: 'system', }; const rule = getPartialRulesSchemaMock(); - const signal = buildSignal(doc, rule); + const signal = { + ...buildSignal([doc], rule), + ...additionalSignalFields(doc), + }; const expected: Signal = { parent: { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, - ancestors: [ + parents: [ { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, ], - original_time: '2020-04-20T21:27:45+0000', - original_event: { - action: 'socket_opened', - dataset: 'socket', - kind: 'event', - module: 'system', - }, - status: 'open', - rule: { - created_by: 'elastic', - description: 'Detecting root and admin users', - enabled: true, - false_positives: [], - from: 'now-6m', - id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', - immutable: false, - index: ['auditbeat-*', 'filebeat-*', 'packetbeat-*', 'winlogbeat-*'], - interval: '5m', - risk_score: 50, - rule_id: 'rule-1', - language: 'kuery', - max_signals: 100, - name: 'Detect Root/Admin Users', - output_index: '.siem-signals', - query: 'user.name: root or user.name: admin', - references: ['http://www.example.com', 'https://ww.example.com'], - severity: 'high', - updated_by: 'elastic', - tags: ['some fake tag 1', 'some fake tag 2'], - to: 'now', - type: 'query', - note: '', - updated_at: signal.rule.updated_at, - created_at: signal.rule.created_at, - }, - }; - expect(signal).toEqual(expected); - }); - - test('it builds a signal as expected with original_event if is present and without internal tags in them', () => { - const doc = sampleDocNoSortId('d5e8eb51-a6a0-456d-8a15-4b79bfec3d71'); - doc._source.event = { - action: 'socket_opened', - dataset: 'socket', - kind: 'event', - module: 'system', - }; - const rule = getPartialRulesSchemaMock(); - rule.tags = [ - 'some fake tag 1', - 'some fake tag 2', - `${INTERNAL_RULE_ID_KEY}:rule-1`, - `${INTERNAL_IMMUTABLE_KEY}:true`, - ]; - const signal = buildSignal(doc, rule); - const expected: Signal = { - parent: { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', - id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', - type: 'event', - index: 'myFakeSignalIndex', - depth: 1, - }, ancestors: [ { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, ], original_time: '2020-04-20T21:27:45+0000', @@ -209,6 +150,7 @@ describe('buildSignal', () => { updated_at: signal.rule.updated_at, created_at: signal.rule.created_at, }, + depth: 1, }; expect(signal).toEqual(expected); }); @@ -221,14 +163,12 @@ describe('buildSignal', () => { kind: 'event', module: 'system', }; - const rule = getPartialRulesSchemaMock(); - const signal = buildAncestor(doc, rule); + const signal = buildParent(doc); const expected: Ancestor = { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }; expect(signal).toEqual(expected); }); @@ -242,76 +182,34 @@ describe('buildSignal', () => { module: 'system', }; doc._source.signal = { - parent: { - rule: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', - id: '730ddf9e-5a00-4f85-9ddf-5878ca511a87', - type: 'event', - index: 'myFakeSignalIndex', - depth: 1, - }, - ancestors: [ + parents: [ { - rule: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', id: '730ddf9e-5a00-4f85-9ddf-5878ca511a87', type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, ], - }; - const rule = getPartialRulesSchemaMock(); - const signal = buildAncestor(doc, rule); - const expected: Ancestor = { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', - id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', - type: 'signal', - index: 'myFakeSignalIndex', - depth: 2, - }; - expect(signal).toEqual(expected); - }); - - test('it builds a ancestor correctly if the parent does exist without internal tags in them', () => { - const doc = sampleDocNoSortId('d5e8eb51-a6a0-456d-8a15-4b79bfec3d71'); - doc._source.event = { - action: 'socket_opened', - dataset: 'socket', - kind: 'event', - module: 'system', - }; - doc._source.signal = { - parent: { - rule: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', - id: '730ddf9e-5a00-4f85-9ddf-5878ca511a87', - type: 'event', - index: 'myFakeSignalIndex', - depth: 1, - }, ancestors: [ { - rule: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', id: '730ddf9e-5a00-4f85-9ddf-5878ca511a87', type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, ], + depth: 1, + rule: { + id: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', + }, }; - const rule = getPartialRulesSchemaMock(); - rule.tags = [ - 'some fake tag 1', - 'some fake tag 2', - `${INTERNAL_RULE_ID_KEY}:rule-1`, - `${INTERNAL_IMMUTABLE_KEY}:true`, - ]; - - const signal = buildAncestor(doc, rule); + const signal = buildParent(doc); const expected: Ancestor = { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + rule: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', type: 'signal', index: 'myFakeSignalIndex', - depth: 2, + depth: 1, }; expect(signal).toEqual(expected); }); @@ -324,15 +222,13 @@ describe('buildSignal', () => { kind: 'event', module: 'system', }; - const rule = getPartialRulesSchemaMock(); - const signal = buildAncestorsSignal(doc, rule); + const signal = buildAncestors(doc); const expected: Ancestor[] = [ { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, ]; expect(signal).toEqual(expected); @@ -347,77 +243,43 @@ describe('buildSignal', () => { module: 'system', }; doc._source.signal = { - parent: { - rule: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', - id: '730ddf9e-5a00-4f85-9ddf-5878ca511a87', - type: 'event', - index: 'myFakeSignalIndex', - depth: 1, - }, + parents: [ + { + id: '730ddf9e-5a00-4f85-9ddf-5878ca511a87', + type: 'event', + index: 'myFakeSignalIndex', + depth: 0, + }, + ], ancestors: [ { - rule: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', id: '730ddf9e-5a00-4f85-9ddf-5878ca511a87', type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, ], + rule: { + id: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', + }, + depth: 1, }; - const rule = getPartialRulesSchemaMock(); - const signal = buildAncestorsSignal(doc, rule); + const signal = buildAncestors(doc); const expected: Ancestor[] = [ { - rule: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', id: '730ddf9e-5a00-4f85-9ddf-5878ca511a87', type: 'event', index: 'myFakeSignalIndex', - depth: 1, + depth: 0, }, { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', + rule: '98c0bf9e-4d38-46f4-9a6a-8a820426256b', id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', type: 'signal', index: 'myFakeSignalIndex', - depth: 2, + depth: 1, }, ]; expect(signal).toEqual(expected); }); - - test('it removes internal tags from a typical rule', () => { - const rule = getPartialRulesSchemaMock(); - rule.tags = [ - 'some fake tag 1', - 'some fake tag 2', - `${INTERNAL_RULE_ID_KEY}:rule-1`, - `${INTERNAL_IMMUTABLE_KEY}:true`, - ]; - const noInternals = removeInternalTagsFromRule(rule); - expect(noInternals).toEqual(getPartialRulesSchemaMock()); - }); - - test('it works with an empty array', () => { - const rule = getPartialRulesSchemaMock(); - rule.tags = []; - const noInternals = removeInternalTagsFromRule(rule); - const expected = getPartialRulesSchemaMock(); - expected.tags = []; - expect(noInternals).toEqual(expected); - }); - - test('it works if tags does not exist', () => { - const rule = getPartialRulesSchemaMock(); - delete rule.tags; - const noInternals = removeInternalTagsFromRule(rule); - const expected = getPartialRulesSchemaMock(); - delete expected.tags; - expect(noInternals).toEqual(expected); - }); - - test('it works if tags contains normal values and no internal values', () => { - const rule = getPartialRulesSchemaMock(); - const noInternals = removeInternalTagsFromRule(rule); - expect(noInternals).toEqual(rule); - }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_signal.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_signal.ts index e7098c015c16..78818779dd66 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_signal.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_signal.ts @@ -5,35 +5,41 @@ */ import { RulesSchema } from '../../../../common/detection_engine/schemas/response/rules_schema'; -import { INTERNAL_IDENTIFIER } from '../../../../common/constants'; import { SignalSourceHit, Signal, Ancestor } from './types'; -export const buildAncestor = (doc: SignalSourceHit, rule: Partial): Ancestor => { - const existingSignal = doc._source.signal?.parent; - if (existingSignal != null) { +/** + * Takes a parent signal or event document and extracts the information needed for the corresponding entry in the child + * signal's `signal.parents` array. + * @param doc The parent signal or event + */ +export const buildParent = (doc: SignalSourceHit): Ancestor => { + if (doc._source.signal != null) { return { - rule: rule.id != null ? rule.id : '', + rule: doc._source.signal.rule.id, id: doc._id, type: 'signal', index: doc._index, - depth: existingSignal.depth + 1, + // We first look for signal.depth and use that if it exists. If it doesn't exist, this should be a pre-7.10 signal + // and should have signal.parent.depth instead. signal.parent.depth in this case is treated as equivalent to signal.depth. + depth: doc._source.signal.depth ?? doc._source.signal.parent?.depth ?? 1, }; } else { return { - rule: rule.id != null ? rule.id : '', id: doc._id, type: 'event', index: doc._index, - depth: 1, + depth: 0, }; } }; -export const buildAncestorsSignal = ( - doc: SignalSourceHit, - rule: Partial -): Signal['ancestors'] => { - const newAncestor = buildAncestor(doc, rule); +/** + * Takes a parent signal or event document with N ancestors and adds the parent document to the ancestry array, + * creating an array of N+1 ancestors. + * @param doc The parent signal/event for which to extend the ancestry. + */ +export const buildAncestors = (doc: SignalSourceHit): Ancestor[] => { + const newAncestor = buildParent(doc); const existingAncestors = doc._source.signal?.ancestors; if (existingAncestors != null) { return [...existingAncestors, newAncestor]; @@ -42,35 +48,33 @@ export const buildAncestorsSignal = ( } }; -export const buildSignal = (doc: SignalSourceHit, rule: Partial): Signal => { - const ruleWithoutInternalTags = removeInternalTagsFromRule(rule); - const parent = buildAncestor(doc, rule); - const ancestors = buildAncestorsSignal(doc, rule); - let signal: Signal = { - parent, +/** + * Builds the `signal.*` fields that are common across all signals. + * @param docs The parent signals/events of the new signal to be built. + * @param rule The rule that is generating the new signal. + */ +export const buildSignal = (docs: SignalSourceHit[], rule: Partial): Signal => { + const parents = docs.map(buildParent); + const depth = parents.reduce((acc, parent) => Math.max(parent.depth, acc), 0) + 1; + const ancestors = docs.reduce((acc: Ancestor[], doc) => acc.concat(buildAncestors(doc)), []); + return { + parents, ancestors, - original_time: doc._source['@timestamp'], status: 'open', - rule: ruleWithoutInternalTags, + rule, + depth, }; - if (doc._source.event != null) { - signal = { ...signal, original_event: doc._source.event }; - } - if (doc._source.threshold_count != null) { - signal = { ...signal, threshold_count: doc._source.threshold_count }; - delete doc._source.threshold_count; - } - return signal; }; -export const removeInternalTagsFromRule = (rule: Partial): Partial => { - if (rule.tags == null) { - return rule; - } else { - const ruleWithoutInternalTags: Partial = { - ...rule, - tags: rule.tags.filter((tag) => !tag.startsWith(INTERNAL_IDENTIFIER)), - }; - return ruleWithoutInternalTags; - } +/** + * Creates signal fields that are only available in the special case where a signal has only 1 parent signal/event. + * @param doc The parent signal/event of the new signal to be built. + */ +export const additionalSignalFields = (doc: SignalSourceHit) => { + return { + parent: buildParent(doc), + original_time: doc._source['@timestamp'], + original_event: doc._source.event ?? undefined, + threshold_count: doc._source.threshold_count ?? undefined, + }; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts index da17d4a1f123..7ee157beec78 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -120,7 +120,6 @@ export const signalRulesAlertType = ({ enabled, schedule: { interval }, throttle, - params: ruleParams, } = savedObject.attributes; const updatedAt = savedObject.updated_at ?? ''; const refresh = actions.length ? 'wait_for' : false; @@ -343,7 +342,7 @@ export const signalRulesAlertType = ({ if (result.success) { if (actions.length) { const notificationRuleParams: NotificationRuleTypeParams = { - ...ruleParams, + ...params, name, id: savedObject.id, }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.test.ts index 8b9fb0574efe..41c825ea4d97 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.test.ts @@ -291,37 +291,7 @@ describe('singleBulkCreate', () => { test('filter duplicate rules will return nothing filtered when the two rule ids do not match with each other', () => { const filtered = filterDuplicateRules('some id', sampleDocWithAncestors()); - expect(filtered).toEqual([ - { - _index: 'myFakeSignalIndex', - _type: 'doc', - _score: 100, - _version: 1, - _id: 'e1e08ddc-5e37-49ff-a258-5393aa44435a', - _source: { - someKey: 'someValue', - '@timestamp': '2020-04-20T21:27:45+0000', - signal: { - parent: { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', - id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', - type: 'event', - index: 'myFakeSignalIndex', - depth: 1, - }, - ancestors: [ - { - rule: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', - id: 'd5e8eb51-a6a0-456d-8a15-4b79bfec3d71', - type: 'event', - index: 'myFakeSignalIndex', - depth: 1, - }, - ], - }, - }, - }, - ]); + expect(filtered).toEqual(sampleDocWithAncestors().hits.hits); }); test('filters duplicate rules will return empty array when the two rule ids match each other', () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.ts index 74709f31563e..be71c67615a4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.ts @@ -51,7 +51,10 @@ export const filterDuplicateRules = ( if (doc._source.signal == null) { return true; } else { - return !doc._source.signal.ancestors.some((ancestor) => ancestor.rule === ruleId); + return !( + doc._source.signal.ancestors.some((ancestor) => ancestor.rule === ruleId) || + doc._source.signal.rule.id === ruleId + ); } }); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts index aecdbe10695d..700a8fb5022d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts @@ -44,8 +44,16 @@ export interface SignalSource { [key: string]: SearchTypes; '@timestamp': string; signal?: { - parent: Ancestor; + // parent is deprecated: new signals should populate parents instead + // both are optional until all signals with parent are gone and we can safely remove it + parent?: Ancestor; + parents?: Ancestor[]; ancestors: Ancestor[]; + rule: { + id: string; + }; + // signal.depth doesn't exist on pre-7.10 signals + depth?: number; }; } @@ -113,7 +121,7 @@ export type SignalRuleAlertTypeDefinition = Omit & { }; export interface Ancestor { - rule: string; + rule?: string; id: string; type: string; index: string; @@ -122,12 +130,15 @@ export interface Ancestor { export interface Signal { rule: Partial; - parent: Ancestor; + // DEPRECATED: use parents instead of parent + parent?: Ancestor; + parents: Ancestor[]; ancestors: Ancestor[]; - original_time: string; + original_time?: string; original_event?: SearchTypes; status: Status; threshold_count?: SearchTypes; + depth: number; } export interface SignalHit { diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 24cf1f8746d8..1f4790a8981c 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -315,7 +315,6 @@ export class Plugin implements IPlugin { + const firstSeen = getOr(null, `firstSeen.value_as_string`, networkHit); + const lastSeen = getOr(null, `lastSeen.value_as_string`, networkHit); + const autonomousSystem: AutonomousSystem | null = getOr( + null, + `as.results.hits.hits[0]._source.${type}.as`, + networkHit + ); + const geoFields: GeoEcs | null = getOr( + null, + `geo.results.hits.hits[0]._source.${type}.geo`, + networkHit + ); + + return { + [type]: { + firstSeen, + lastSeen, + autonomousSystem: { + ...autonomousSystem, + }, + geo: { + ...geoFields, + }, + }, + }; +}; + +export const getNetworkDetailsHostAgg = (hostDetailsHit: NetworkDetailsHostHit | {}) => { + const hostFields: HostEcs | null = getOr( + null, + `results.hits.hits[0]._source.host`, + hostDetailsHit + ); + return { + host: { + ...hostFields, + }, + }; +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/details/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/details/index.ts new file mode 100644 index 000000000000..8b2b79c4cd40 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/details/index.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { getOr } from 'lodash/fp'; + +import { IEsSearchResponse } from '../../../../../../../../../src/plugins/data/common'; + +import { + NetworkDetailsStrategyResponse, + NetworkQueries, + NetworkDetailsRequestOptions, +} from '../../../../../../common/search_strategy/security_solution/network'; + +import { inspectStringifyObject } from '../../../../../utils/build_query'; +import { SecuritySolutionFactory } from '../../types'; + +import { getNetworkDetailsAgg, getNetworkDetailsHostAgg } from './helpers'; +import { buildNetworkDetailsQuery } from './query.details_network.dsl'; + +export const networkDetails: SecuritySolutionFactory = { + buildDsl: (options: NetworkDetailsRequestOptions) => buildNetworkDetailsQuery(options), + parse: async ( + options: NetworkDetailsRequestOptions, + response: IEsSearchResponse + ): Promise => { + const inspect = { + dsl: [inspectStringifyObject(buildNetworkDetailsQuery(options))], + }; + + return { + ...response, + inspect, + networkDetails: { + ...getNetworkDetailsAgg('source', getOr({}, 'aggregations.source', response.rawResponse)), + ...getNetworkDetailsAgg( + 'destination', + getOr({}, 'aggregations.destination', response.rawResponse) + ), + ...getNetworkDetailsHostAgg(getOr({}, 'aggregations.host', response.rawResponse)), + }, + }; + }, +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/details/query.details_network.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/details/query.details_network.dsl.ts new file mode 100644 index 000000000000..67aeba60c4d2 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/details/query.details_network.dsl.ts @@ -0,0 +1,126 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { isEmpty } from 'lodash/fp'; +import { NetworkDetailsRequestOptions } from '../../../../../../common/search_strategy/security_solution/network'; + +const getAggs = (type: string, ip: string) => { + return { + [type]: { + filter: { + term: { + [`${type}.ip`]: ip, + }, + }, + aggs: { + firstSeen: { + min: { + field: '@timestamp', + }, + }, + lastSeen: { + max: { + field: '@timestamp', + }, + }, + as: { + filter: { + exists: { + field: `${type}.as`, + }, + }, + aggs: { + results: { + top_hits: { + size: 1, + _source: [`${type}.as`], + sort: [ + { + '@timestamp': 'desc', + }, + ], + }, + }, + }, + }, + geo: { + filter: { + exists: { + field: `${type}.geo`, + }, + }, + aggs: { + results: { + top_hits: { + size: 1, + _source: [`${type}.geo`], + sort: [ + { + '@timestamp': 'desc', + }, + ], + }, + }, + }, + }, + }, + }, + }; +}; + +const getHostAggs = (ip: string) => { + return { + host: { + filter: { + term: { + 'host.ip': ip, + }, + }, + aggs: { + results: { + top_hits: { + size: 1, + _source: ['host'], + sort: [ + { + '@timestamp': 'desc', + }, + ], + }, + }, + }, + }, + }; +}; + +export const buildNetworkDetailsQuery = ({ + defaultIndex, + docValueFields, + ip, +}: NetworkDetailsRequestOptions) => { + const dslQuery = { + allowNoIndices: true, + index: defaultIndex, + ignoreUnavailable: true, + body: { + ...(isEmpty(docValueFields) ? { docvalue_fields: docValueFields } : {}), + aggs: { + ...getAggs('source', ip), + ...getAggs('destination', ip), + ...getHostAggs(ip), + }, + query: { + bool: { + should: [], + }, + }, + size: 0, + track_total_hits: false, + }, + }; + + return dslQuery; +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/index.ts index 3b927b858999..bf5321d32b58 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/index.ts @@ -10,18 +10,22 @@ import { } from '../../../../../common/search_strategy/security_solution'; import { SecuritySolutionFactory } from '../types'; +import { networkDetails } from './details'; import { networkDns } from './dns'; import { networkHttp } from './http'; import { networkOverview } from './overview'; import { networkTls } from './tls'; import { networkTopCountries } from './top_countries'; import { networkTopNFlow } from './top_n_flow'; +import { networkUsers } from './users'; export const networkFactory: Record> = { + [NetworkQueries.details]: networkDetails, [NetworkQueries.dns]: networkDns, [NetworkQueries.http]: networkHttp, [NetworkQueries.overview]: networkOverview, [NetworkQueries.tls]: networkTls, [NetworkQueries.topCountries]: networkTopCountries, [NetworkQueries.topNFlow]: networkTopNFlow, + [NetworkQueries.users]: networkUsers, }; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/helpers.ts index 59359fd35a34..40653007ef43 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/helpers.ts @@ -8,16 +8,16 @@ import { getOr } from 'lodash/fp'; import { IEsSearchResponse } from '../../../../../../../../../src/plugins/data/common'; import { - TlsBuckets, - TlsEdges, + NetworkTlsBuckets, + NetworkTlsEdges, } from '../../../../../../common/search_strategy/security_solution/network'; -export const getTlsEdges = (response: IEsSearchResponse): TlsEdges[] => - formatTlsEdges(getOr([], 'aggregations.sha1.buckets', response.rawResponse)); +export const getNetworkTlsEdges = (response: IEsSearchResponse): NetworkTlsEdges[] => + formatNetworkTlsEdges(getOr([], 'aggregations.sha1.buckets', response.rawResponse)); -export const formatTlsEdges = (buckets: TlsBuckets[]): TlsEdges[] => - buckets.map((bucket: TlsBuckets) => { - const edge: TlsEdges = { +export const formatNetworkTlsEdges = (buckets: NetworkTlsBuckets[]): NetworkTlsEdges[] => + buckets.map((bucket: NetworkTlsBuckets) => { + const edge: NetworkTlsEdges = { node: { _id: bucket.key, subjects: bucket.subjects.buckets.map(({ key }) => key), diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/index.ts index 32836c0ef686..46556f46d3a5 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/index.ts @@ -13,21 +13,21 @@ import { NetworkTlsStrategyResponse, NetworkQueries, NetworkTlsRequestOptions, - TlsEdges, + NetworkTlsEdges, } from '../../../../../../common/search_strategy/security_solution/network'; import { inspectStringifyObject } from '../../../../../utils/build_query'; import { SecuritySolutionFactory } from '../../types'; -import { getTlsEdges } from './helpers'; -import { buildTlsQuery } from './query.tls_network.dsl'; +import { getNetworkTlsEdges } from './helpers'; +import { buildNetworkTlsQuery } from './query.tls_network.dsl'; export const networkTls: SecuritySolutionFactory = { buildDsl: (options: NetworkTlsRequestOptions) => { if (options.pagination && options.pagination.querySize >= DEFAULT_MAX_TABLE_QUERY_SIZE) { throw new Error(`No query size above ${DEFAULT_MAX_TABLE_QUERY_SIZE}`); } - return buildTlsQuery(options); + return buildNetworkTlsQuery(options); }, parse: async ( options: NetworkTlsRequestOptions, @@ -35,12 +35,11 @@ export const networkTls: SecuritySolutionFactory = { ): Promise => { const { activePage, cursorStart, fakePossibleCount, querySize } = options.pagination; const totalCount = getOr(0, 'aggregations.count.value', response.rawResponse); - const tlsEdges: TlsEdges[] = getTlsEdges(response); + const networkTlsEdges: NetworkTlsEdges[] = getNetworkTlsEdges(response); const fakeTotalCount = fakePossibleCount <= totalCount ? fakePossibleCount : totalCount; - const edges = tlsEdges.splice(cursorStart, querySize - cursorStart); + const edges = networkTlsEdges.splice(cursorStart, querySize - cursorStart); const inspect = { - dsl: [inspectStringifyObject(buildTlsQuery(options))], - response: [inspectStringifyObject(response)], + dsl: [inspectStringifyObject(buildNetworkTlsQuery(options))], }; const showMorePagesIndicator = totalCount > fakeTotalCount; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/query.tls_network.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/query.tls_network.dsl.ts index 6e5ba0674a0e..adf11175479e 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/query.tls_network.dsl.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/tls/query.tls_network.dsl.ts @@ -8,13 +8,13 @@ import { assertUnreachable } from '../../../../../../common/utility_types'; import { createQueryFilterClauses } from '../../../../../utils/build_query'; import { + Direction, NetworkTlsRequestOptions, + NetworkTlsFields, SortField, - Direction, - TlsFields, } from '../../../../../../common/search_strategy'; -const getAggs = (querySize: number, sort: SortField) => ({ +const getAggs = (querySize: number, sort: SortField) => ({ count: { cardinality: { field: 'tls.server.hash.sha1', @@ -53,7 +53,7 @@ const getAggs = (querySize: number, sort: SortField) => ({ }, }); -export const buildTlsQuery = ({ +export const buildNetworkTlsQuery = ({ ip, sort, filterQuery, @@ -98,9 +98,9 @@ interface QueryOrder { _key: Direction; } -const getQueryOrder = (sort: SortField): QueryOrder => { +const getQueryOrder = (sort: SortField): QueryOrder => { switch (sort.field) { - case TlsFields._id: + case NetworkTlsFields._id: return { _key: sort.direction }; default: return assertUnreachable(sort.field); diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/users/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/users/helpers.ts new file mode 100644 index 000000000000..4068721e667a --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/users/helpers.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { get, getOr } from 'lodash/fp'; +import { IEsSearchResponse } from '../../../../../../../../../src/plugins/data/common'; +import { + NetworkUsersBucketsItem, + NetworkUsersEdges, +} from '../../../../../../common/search_strategy/security_solution/network'; + +export const getUsersEdges = (response: IEsSearchResponse): NetworkUsersEdges[] => + getOr([], `aggregations.users.buckets`, response.rawResponse).map( + (bucket: NetworkUsersBucketsItem) => ({ + node: { + _id: bucket.key, + user: { + id: getOr([], 'id.buckets', bucket).map((id: NetworkUsersBucketsItem) => id.key), + name: bucket.key, + groupId: getOr([], 'groupId.buckets', bucket).map( + (groupId: NetworkUsersBucketsItem) => groupId.key + ), + groupName: getOr([], 'groupName.buckets', bucket).map( + (groupName: NetworkUsersBucketsItem) => groupName.key + ), + count: get('doc_count', bucket), + }, + }, + cursor: { + value: bucket.key, + tiebreaker: null, + }, + }) + ); diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/users/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/users/index.ts new file mode 100644 index 000000000000..f9b9a2fd2747 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/users/index.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { getOr } from 'lodash/fp'; + +import { IEsSearchResponse } from '../../../../../../../../../src/plugins/data/common'; + +import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../../common/constants'; +import { + NetworkUsersStrategyResponse, + NetworkQueries, + NetworkUsersRequestOptions, +} from '../../../../../../common/search_strategy/security_solution/network'; + +import { inspectStringifyObject } from '../../../../../utils/build_query'; +import { SecuritySolutionFactory } from '../../types'; + +import { getUsersEdges } from './helpers'; +import { buildUsersQuery } from './query.users_network.dsl'; + +export const networkUsers: SecuritySolutionFactory = { + buildDsl: (options: NetworkUsersRequestOptions) => { + if (options.pagination && options.pagination.querySize >= DEFAULT_MAX_TABLE_QUERY_SIZE) { + throw new Error(`No query size above ${DEFAULT_MAX_TABLE_QUERY_SIZE}`); + } + return buildUsersQuery(options); + }, + parse: async ( + options: NetworkUsersRequestOptions, + response: IEsSearchResponse + ): Promise => { + const { activePage, cursorStart, fakePossibleCount, querySize } = options.pagination; + const totalCount = getOr(0, 'aggregations.user_count.value', response.rawResponse); + const usersEdges = getUsersEdges(response); + const fakeTotalCount = fakePossibleCount <= totalCount ? fakePossibleCount : totalCount; + const edges = usersEdges.splice(cursorStart, querySize - cursorStart); + const inspect = { + dsl: [inspectStringifyObject(buildUsersQuery(options))], + }; + const showMorePagesIndicator = totalCount > fakeTotalCount; + + return { + ...response, + edges, + inspect, + pageInfo: { + activePage: activePage ? activePage : 0, + fakeTotalCount, + showMorePagesIndicator, + }, + totalCount, + }; + }, +}; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/users/query.users_network.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/users/query.users_network.dsl.ts new file mode 100644 index 000000000000..386e83b95504 --- /dev/null +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network/users/query.users_network.dsl.ts @@ -0,0 +1,104 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { assertUnreachable } from '../../../../../../common/utility_types'; +import { + Direction, + SortField, + NetworkUsersRequestOptions, + NetworkUsersFields, +} from '../../../../../../common/search_strategy'; +import { createQueryFilterClauses } from '../../../../../utils/build_query'; + +export const buildUsersQuery = ({ + ip, + sort, + filterQuery, + flowTarget, + pagination: { querySize }, + defaultIndex, + timerange: { from, to }, +}: NetworkUsersRequestOptions) => { + const filter = [ + ...createQueryFilterClauses(filterQuery), + { + range: { + '@timestamp': { gte: from, lte: to, format: 'strict_date_optional_time' }, + }, + }, + { term: { [`${flowTarget}.ip`]: ip } }, + ]; + + const dslQuery = { + allowNoIndices: true, + index: defaultIndex, + ignoreUnavailable: true, + body: { + aggs: { + user_count: { + cardinality: { + field: 'user.name', + }, + }, + users: { + terms: { + field: 'user.name', + size: querySize, + order: { + ...getQueryOrder(sort), + }, + }, + aggs: { + id: { + terms: { + field: 'user.id', + }, + }, + groupId: { + terms: { + field: 'user.group.id', + }, + }, + groupName: { + terms: { + field: 'user.group.name', + }, + }, + }, + }, + }, + query: { + bool: { + filter, + must_not: [ + { + term: { + 'event.category': 'authentication', + }, + }, + ], + }, + }, + size: 0, + track_total_hits: false, + }, + }; + + return dslQuery; +}; + +type QueryOrder = { _count: Direction } | { _key: Direction }; + +const getQueryOrder = (sort: SortField): QueryOrder => { + switch (sort.field) { + case NetworkUsersFields.name: + return { _key: sort.direction }; + case NetworkUsersFields.count: + return { _count: sort.direction }; + default: + return assertUnreachable(sort.field); + } +}; diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/policy_form.helpers.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/policy_form.helpers.ts index a3ab829ab642..ab2963223f67 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/policy_form.helpers.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/policy_form.helpers.ts @@ -56,4 +56,6 @@ export type PolicyFormTestSubjects = | 'showAdvancedCronLink' | 'snapshotNameInput' | 'dataStreamBadge' + | 'repositoryNotFoundWarning' + | 'repositorySelect' | 'submitButton'; diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_add.test.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_add.test.ts index dc568161d4fb..f7d6a60703bc 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_add.test.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_add.test.ts @@ -67,6 +67,11 @@ describe('', () => { expect(find('nextButton').props().disabled).toBe(true); }); + test('should not show repository-not-found warning', () => { + const { exists } = testBed; + expect(exists('repositoryNotFoundWarning')).toBe(false); + }); + describe('form validation', () => { describe('logistics (step 1)', () => { test('should require a policy name', async () => { diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_edit.test.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_edit.test.ts index a5b2ec73b85c..7c095256bd10 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_edit.test.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_edit.test.ts @@ -52,6 +52,44 @@ describe('', () => { expect(find('pageTitle').text()).toEqual('Edit policy'); }); + describe('policy with pre-existing repository that was deleted', () => { + beforeEach(async () => { + httpRequestsMockHelpers.setGetPolicyResponse({ policy: POLICY_EDIT }); + httpRequestsMockHelpers.setLoadIndicesResponse({ + indices: ['my_index'], + dataStreams: ['my_data_stream'], + }); + httpRequestsMockHelpers.setLoadRepositoriesResponse({ + repositories: [{ name: 'this-is-a-new-repository' }], + }); + + testBed = await setup(); + + await act(async () => { + await nextTick(); + testBed.component.update(); + }); + }); + + test('should show repository-not-found warning', () => { + const { exists, find } = testBed; + expect(exists('repositoryNotFoundWarning')).toBe(true); + // The select should be an empty string to allow users to select a new repository + expect(find('repositorySelect').props().value).toBe(''); + }); + + describe('validation', () => { + test('should block navigating to next step', () => { + const { exists, find, actions } = testBed; + actions.clickNextButton(); + // Assert that we are still on the repository configuration step + expect(exists('repositoryNotFoundWarning')).toBe(true); + // The select should be an empty string to allow users to select a new repository + expect(find('repositorySelect').props().value).toBe(''); + }); + }); + }); + /** * As the "edit" policy component uses the same form underneath that * the "create" policy, we won't test it again but simply make sure that diff --git a/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx b/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx index 8a7338f4db4e..7d3ba92cf2ad 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_logistics.tsx @@ -18,6 +18,8 @@ import { EuiLink, EuiSpacer, EuiText, + EuiCallOut, + EuiCode, } from '@elastic/eui'; import { Repository } from '../../../../../common/types'; @@ -49,11 +51,15 @@ export const PolicyStepLogistics: React.FunctionComponent = ({ name: undefined, }, }, - sendRequest: reloadRepositories, + resendRequest: reloadRepositories, } = useLoadRepositories(); const { i18n, history } = useServices(); + const [showRepositoryNotFoundWarning, setShowRepositoryNotFoundWarning] = useState( + false + ); + // State for touched inputs const [touched, setTouched] = useState({ name: false, @@ -256,13 +262,26 @@ export const PolicyStepLogistics: React.FunctionComponent = ({ } } + const doesRepositoryExist = + !!policy.repository && + repositories.some((r: { name: string }) => r.name === policy.repository); + + if (!doesRepositoryExist && !errors.repository) { + updatePolicy(policy, { repositoryDoesNotExist: true }); + } + + if (showRepositoryNotFoundWarning !== !doesRepositoryExist) { + setShowRepositoryNotFoundWarning(!doesRepositoryExist); + } + return ( ({ value: name, text: name, }))} - value={policy.repository || repositories[0].name} + hasNoInitialSelection={!doesRepositoryExist} + value={!doesRepositoryExist ? '' : policy.repository} onBlur={() => setTouched({ ...touched, repository: true })} onChange={(e) => { updatePolicy( @@ -541,8 +560,31 @@ export const PolicyStepLogistics: React.FunctionComponent = ({ - + {showRepositoryNotFoundWarning && ( + <> + + + } + color="danger" + iconType="alert" + > + {policy.repository} }} + /> + + + )} + + {renderNameField()} {renderSnapshotNameField()} {renderRepositoryField()} diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_details/policy_details.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_details/policy_details.tsx index f67e8eb58623..b4612c9df42f 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_details/policy_details.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_details/policy_details.tsx @@ -65,7 +65,7 @@ export const PolicyDetails: React.FunctionComponent = ({ onPolicyExecuted, }) => { const { i18n, uiMetricService, history } = useServices(); - const { error, data: policyDetails, sendRequest: reload } = useLoadPolicy(policyName); + const { error, data: policyDetails, resendRequest: reload } = useLoadPolicy(policyName); const [activeTab, setActiveTab] = useState(TAB_SUMMARY); const [isPopoverOpen, setIsPopoverOpen] = useState(false); diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_list.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_list.tsx index 655bd0e9d8bb..57f18ccbf815 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_list.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_list.tsx @@ -45,7 +45,7 @@ export const PolicyList: React.FunctionComponent { diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_table/policy_table.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_table/policy_table.tsx index d55bbf0b324c..e7e4a9b54ada 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_table/policy_table.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/policy_list/policy_table/policy_table.tsx @@ -21,7 +21,7 @@ import { } from '@elastic/eui'; import { SlmPolicy } from '../../../../../../common/types'; -import { Error } from '../../../../../shared_imports'; +import { UseRequestResponse } from '../../../../../shared_imports'; import { UIM_POLICY_SHOW_DETAILS_CLICK } from '../../../../constants'; import { useServices } from '../../../../app_context'; import { @@ -30,13 +30,12 @@ import { PolicyDeleteProvider, } from '../../../../components'; import { linkToAddPolicy, linkToEditPolicy } from '../../../../services/navigation'; -import { SendRequestResponse } from '../../../../../shared_imports'; import { reactRouterNavigate } from '../../../../../../../../../src/plugins/kibana_react/public'; interface Props { policies: SlmPolicy[]; - reload: () => Promise>; + reload: UseRequestResponse['resendRequest']; openPolicyDetailsUrl: (name: SlmPolicy['name']) => string; onPolicyDeleted: (policiesDeleted: Array) => void; onPolicyExecuted: () => void; diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_list.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_list.tsx index 9afdad3806de..a3f57ce4fbf5 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_list.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/repository_list/repository_list.tsx @@ -40,7 +40,7 @@ export const RepositoryList: React.FunctionComponent Promise>; + reload: UseRequestResponse['resendRequest']; openRepositoryDetailsUrl: (name: Repository['name']) => string; onRepositoryDeleted: (repositoriesDeleted: Array) => void; } diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/restore_list/restore_list.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/restore_list/restore_list.tsx index d7a82386926c..d9507a101bba 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/restore_list/restore_list.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/restore_list/restore_list.tsx @@ -52,9 +52,13 @@ export const RestoreList: React.FunctionComponent = () => { const [currentInterval, setCurrentInterval] = useState(INTERVAL_OPTIONS[1]); // Load restores - const { error, isLoading, data: restores = [], isInitialRequest, sendRequest } = useLoadRestores( - currentInterval - ); + const { + error, + isLoading, + data: restores = [], + isInitialRequest, + resendRequest, + } = useLoadRestores(currentInterval); const { uiMetricService, history } = useServices(); @@ -174,7 +178,7 @@ export const RestoreList: React.FunctionComponent = () => { key={interval} icon="empty" onClick={() => { - sendRequest(); + resendRequest(); setCurrentInterval(interval); setIsIntervalMenuOpen(false); }} diff --git a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_list.tsx b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_list.tsx index d13188fc4473..97def33ffe8f 100644 --- a/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_list.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/sections/home/snapshot_list/snapshot_list.tsx @@ -44,7 +44,7 @@ export const SnapshotList: React.FunctionComponent Promise>; + reload: UseRequestResponse['resendRequest']; openSnapshotDetailsUrl: (repositoryName: string, snapshotId: string) => string; repositoryFilter?: string; policyFilter?: string; diff --git a/x-pack/plugins/snapshot_restore/public/application/services/validation/validate_policy.ts b/x-pack/plugins/snapshot_restore/public/application/services/validation/validate_policy.ts index 4314b703722f..b371ec9f8fe8 100644 --- a/x-pack/plugins/snapshot_restore/public/application/services/validation/validate_policy.ts +++ b/x-pack/plugins/snapshot_restore/public/application/services/validation/validate_policy.ts @@ -41,6 +41,12 @@ export interface ValidatePolicyHelperData { * are not configuring this value - like when they are on a previous step. */ validateIndicesCount?: boolean; + + /** + * A policy might be configured with a repository that no longer exists. We want the form to + * block in this case because just having a repository configured is not enough for validity. + */ + repositoryDoesNotExist?: boolean; } export const validatePolicy = ( @@ -50,7 +56,13 @@ export const validatePolicy = ( const i18n = textService.i18n; const { name, snapshotName, schedule, repository, config, retention } = policy; - const { managedRepository, isEditing, policyName, validateIndicesCount } = validationHelperData; + const { + managedRepository, + isEditing, + policyName, + validateIndicesCount, + repositoryDoesNotExist, + } = validationHelperData; const validation: PolicyValidation = { isValid: true, @@ -99,7 +111,7 @@ export const validatePolicy = ( ); } - if (isStringEmpty(repository)) { + if (isStringEmpty(repository) || repositoryDoesNotExist) { validation.errors.repository.push( i18n.translate('xpack.snapshotRestore.policyValidation.repositoryRequiredErrorMessage', { defaultMessage: 'Repository is required.', diff --git a/x-pack/plugins/snapshot_restore/public/shared_imports.ts b/x-pack/plugins/snapshot_restore/public/shared_imports.ts index cad8ce147bd2..bd1c0e0cd395 100644 --- a/x-pack/plugins/snapshot_restore/public/shared_imports.ts +++ b/x-pack/plugins/snapshot_restore/public/shared_imports.ts @@ -14,6 +14,7 @@ export { sendRequest, SendRequestConfig, SendRequestResponse, + UseRequestResponse, useAuthorizationContext, useRequest, UseRequestConfig, diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_mode_control.tsx b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_mode_control.tsx index 42fbf8954396..c3e631e335ea 100644 --- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_mode_control.tsx +++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_mode_control.tsx @@ -37,8 +37,7 @@ const createNewCopiesDisabled = { tooltip: i18n.translate( 'xpack.spaces.management.copyToSpace.copyModeControl.createNewCopies.disabledText', { - defaultMessage: - 'Check if each object was previously copied or imported into the destination space.', + defaultMessage: 'Check if objects were previously copied or imported into the space.', } ), }; @@ -50,33 +49,36 @@ const createNewCopiesEnabled = { ), tooltip: i18n.translate( 'xpack.spaces.management.copyToSpace.copyModeControl.createNewCopies.enabledText', - { defaultMessage: 'All copied objects will be created with new random IDs.' } + { + defaultMessage: + 'Use this option to create one or more copies of the object in the same space.', + } ), }; const overwriteEnabled = { id: 'overwriteEnabled', label: i18n.translate( 'xpack.spaces.management.copyToSpace.copyModeControl.overwrite.enabledLabel', - { defaultMessage: 'Automatically try to overwrite conflicts' } + { defaultMessage: 'Automatically overwrite conflicts' } ), }; const overwriteDisabled = { id: 'overwriteDisabled', label: i18n.translate( 'xpack.spaces.management.copyToSpace.copyModeControl.overwrite.disabledLabel', - { defaultMessage: 'Request action when conflict occurs' } + { defaultMessage: 'Request action on conflict' } ), }; const includeRelated = { id: 'includeRelated', text: i18n.translate('xpack.spaces.management.copyToSpace.copyModeControl.includeRelated.title', { - defaultMessage: 'Include related saved objects', + defaultMessage: 'Include related objects', }), tooltip: i18n.translate( 'xpack.spaces.management.copyToSpace.copyModeControl.includeRelated.text', { defaultMessage: - 'This will copy any other objects this has references to -- for example, a dashboard may have references to multiple visualizations.', + 'Copy this object and its related objects. For dashboards, related visualizations, index patterns, and saved searches are also copied.', } ), }; @@ -86,7 +88,7 @@ const copyOptionsTitle = i18n.translate( ); const relationshipOptionsTitle = i18n.translate( 'xpack.spaces.management.copyToSpace.copyModeControl.relationshipOptionsTitle', - { defaultMessage: 'Relationship options' } + { defaultMessage: 'Relationship' } ); const createLabel = ({ text, tooltip }: { text: string; tooltip: string }) => ( diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_status_indicator.tsx b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_status_indicator.tsx index 158d7a9a43ef..d9e1418cdd41 100644 --- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_status_indicator.tsx +++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_status_indicator.tsx @@ -5,7 +5,7 @@ */ import React, { Fragment } from 'react'; -import { EuiLoadingSpinner, EuiIconTip, EuiSpacer } from '@elastic/eui'; +import { EuiLoadingSpinner, EuiIconTip } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { ImportRetry } from '../types'; import { SummarizedCopyToSpaceResult, SummarizedSavedObjectResult } from '..'; @@ -36,13 +36,13 @@ export const CopyStatusIndicator = (props: Props) => { // the object was overwritten ) : ( // the object was not overwritten ); return ; @@ -53,19 +53,19 @@ export const CopyStatusIndicator = (props: Props) => { // this is an "automatic overwrite", e.g., the "Overwrite all conflicts" option was selected ) : pendingObjectRetry?.overwrite ? ( // this is a manual overwrite, e.g., the individual "Overwrite?" switch was enabled ) : ( // this object is pending success, but it will not result in an overwrite ); return ; @@ -80,7 +80,7 @@ export const CopyStatusIndicator = (props: Props) => { content={ } /> @@ -88,28 +88,38 @@ export const CopyStatusIndicator = (props: Props) => { } if (hasConflicts) { - return ( - - - - - - } - /> - ); + switch (conflict!.error.type) { + case 'conflict': + return ( + + + + } + /> + ); + case 'ambiguous_conflict': + return ( + + + + } + /> + ); + } } return hasMissingReferences ? ( @@ -121,17 +131,17 @@ export const CopyStatusIndicator = (props: Props) => { overwrite ? ( ) : conflict ? ( ) : ( ) } diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_status_summary_indicator.tsx b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_status_summary_indicator.tsx index 4bc7e5cfaf31..4dfb14e756cd 100644 --- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_status_summary_indicator.tsx +++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_status_summary_indicator.tsx @@ -55,7 +55,7 @@ const renderIcon = (props: Props) => { content={ } @@ -93,7 +93,7 @@ const renderIcon = (props: Props) => { content={ } @@ -119,7 +119,7 @@ const renderIcon = (props: Props) => { content={ } diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout.test.tsx b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout.test.tsx index dfc908d81887..e214db22aa9c 100644 --- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout.test.tsx +++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_flyout.test.tsx @@ -510,7 +510,7 @@ describe('CopyToSpaceFlyout', () => { Object { "color": "warning", "content": , @@ -604,7 +604,7 @@ describe('CopyToSpaceFlyout', () => { Object { "color": "danger", "content": , diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_form.tsx b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_form.tsx index fdc8d8c73e32..551573feebcd 100644 --- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_form.tsx +++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/copy_to_space_form.tsx @@ -51,7 +51,7 @@ export const CopyToSpaceForm = (props: Props) => { label={ } fullWidth diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/processing_copy_to_space.tsx b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/processing_copy_to_space.tsx index ceaa1dc9f5e2..ab8fb0b438f6 100644 --- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/processing_copy_to_space.tsx +++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/processing_copy_to_space.tsx @@ -45,36 +45,30 @@ const renderCopyOptions = ({ createNewCopies, overwrite, includeRelated }: CopyO defaultMessage="Check for existing objects" /> ); - const overwriteLabel = overwrite ? ( - - ) : ( - - ); - const includeRelatedLabel = includeRelated ? ( - - ) : ( - - ); return ( {!createNewCopies && ( - + + } + /> )} - + + } + /> ); }; diff --git a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/selectable_spaces_control.tsx b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/selectable_spaces_control.tsx index 2a8b5e660f38..d4e12b31b5b4 100644 --- a/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/selectable_spaces_control.tsx +++ b/x-pack/plugins/spaces/public/copy_saved_objects_to_space/components/selectable_spaces_control.tsx @@ -31,7 +31,7 @@ export const SelectableSpacesControl = (props: Props) => { content={ } position="left" diff --git a/x-pack/plugins/spaces/public/management/components/confirm_delete_modal/__snapshots__/confirm_delete_modal.test.tsx.snap b/x-pack/plugins/spaces/public/management/components/confirm_delete_modal/__snapshots__/confirm_delete_modal.test.tsx.snap index 6e422bc13f06..b0d0933614d1 100644 --- a/x-pack/plugins/spaces/public/management/components/confirm_delete_modal/__snapshots__/confirm_delete_modal.test.tsx.snap +++ b/x-pack/plugins/spaces/public/management/components/confirm_delete_modal/__snapshots__/confirm_delete_modal.test.tsx.snap @@ -55,6 +55,7 @@ exports[`ConfirmDeleteModal renders as expected 1`] = ` labelType="label" > { })} > { values={{ rolesLink: ( diff --git a/x-pack/plugins/spaces/public/management/components/unauthorized_prompt/__snapshots__/unauthorized_prompt.test.tsx.snap b/x-pack/plugins/spaces/public/management/components/unauthorized_prompt/__snapshots__/unauthorized_prompt.test.tsx.snap index b53b4d6ec7ca..1e761a0f14fc 100644 --- a/x-pack/plugins/spaces/public/management/components/unauthorized_prompt/__snapshots__/unauthorized_prompt.test.tsx.snap +++ b/x-pack/plugins/spaces/public/management/components/unauthorized_prompt/__snapshots__/unauthorized_prompt.test.tsx.snap @@ -7,7 +7,7 @@ exports[`UnauthorizedPrompt renders as expected 1`] = ` data-test-subj="permissionDeniedMessage" > diff --git a/x-pack/plugins/spaces/public/management/components/unauthorized_prompt/unauthorized_prompt.tsx b/x-pack/plugins/spaces/public/management/components/unauthorized_prompt/unauthorized_prompt.tsx index dd3f96d94eab..50f10ec3860d 100644 --- a/x-pack/plugins/spaces/public/management/components/unauthorized_prompt/unauthorized_prompt.tsx +++ b/x-pack/plugins/spaces/public/management/components/unauthorized_prompt/unauthorized_prompt.tsx @@ -24,7 +24,7 @@ export const UnauthorizedPrompt = () => (

} diff --git a/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space_avatar.test.tsx.snap b/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space_avatar.test.tsx.snap index 269b2b690818..058b9ecdd0f8 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space_avatar.test.tsx.snap +++ b/x-pack/plugins/spaces/public/management/edit_space/customize_space/__snapshots__/customize_space_avatar.test.tsx.snap @@ -14,6 +14,7 @@ exports[`renders without crashing 1`] = ` labelType="label" > { > { )} { fullWidth > { > { > { > { id="xpack.spaces.management.spaceIdentifier.urlIdentifierLabel" defaultMessage="URL identifier " /> - + {editLinkText}

diff --git a/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap b/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap index 43ae75b74c88..3835fa085c26 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap +++ b/x-pack/plugins/spaces/public/management/edit_space/enabled_features/__snapshots__/enabled_features.test.tsx.snap @@ -68,6 +68,7 @@ exports[`EnabledFeatures renders as expected 1`] = ` values={ Object { "rolesLink": { values={{ rolesLink: ( { return ( { return ( diff --git a/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx b/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx index a98fae256182..36efc6874978 100644 --- a/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx +++ b/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx @@ -140,7 +140,11 @@ export class SpacesGridPage extends Component { public getPrimaryActionButton() { return ( - + { { render: (record: Space) => ( { available: (record: Space) => !isReservedSpace(record), render: (record: Space) => ( diff --git a/x-pack/plugins/spaces/public/nav_control/components/manage_spaces_button.tsx b/x-pack/plugins/spaces/public/nav_control/components/manage_spaces_button.tsx index 98467ebdb790..6ac637d6b31d 100644 --- a/x-pack/plugins/spaces/public/nav_control/components/manage_spaces_button.tsx +++ b/x-pack/plugins/spaces/public/nav_control/components/manage_spaces_button.tsx @@ -32,6 +32,7 @@ export class ManageSpacesButton extends Component { isDisabled={this.props.isDisabled} onClick={this.navigateToManageSpaces} style={this.props.style} + data-test-subj="manageSpaces" > { return ( { const title = currentNamespaces.length === 1 ? i18n.translate('xpack.spaces.management.shareToSpace.shareNewSuccessTitle', { - defaultMessage: 'Saved Object is now shared!', + defaultMessage: 'Object is now shared', }) : i18n.translate('xpack.spaces.management.shareToSpace.shareEditSuccessTitle', { - defaultMessage: 'Saved Object updated', + defaultMessage: 'Object was updated', }); if (spacesToAdd.length > 0) { await spacesManager.shareSavedObjectAdd({ type, id }, spacesToAdd); const spaceNames = spacesToAdd.map( (spaceId) => spaces.find((space) => space.id === spaceId)!.name ); - const text = i18n.translate('xpack.spaces.management.shareToSpace.shareAddSuccessText', { - defaultMessage: `'{object}' was added to the following spaces:\n{spaces}`, - values: { object: meta.title, spaces: spaceNames.join(', ') }, - }); + const spaceCount = spaceNames.length; + const text = + spaceCount === 1 + ? i18n.translate('xpack.spaces.management.shareToSpace.shareAddSuccessTextSingular', { + defaultMessage: `'{object}' was added to 1 space.`, + values: { object: meta.title }, + }) + : i18n.translate('xpack.spaces.management.shareToSpace.shareAddSuccessTextPlural', { + defaultMessage: `'{object}' was added to {spaceCount} spaces.`, + values: { object: meta.title, spaceCount }, + }); toastNotifications.addSuccess({ title, text }); } if (spacesToRemove.length > 0) { @@ -125,10 +132,20 @@ export const ShareSavedObjectsToSpaceFlyout = (props: Props) => { const spaceNames = spacesToRemove.map( (spaceId) => spaces.find((space) => space.id === spaceId)!.name ); - const text = i18n.translate('xpack.spaces.management.shareToSpace.shareRemoveSuccessText', { - defaultMessage: `'{object}' was removed from the following spaces:\n{spaces}`, - values: { object: meta.title, spaces: spaceNames.join(', ') }, - }); + const spaceCount = spaceNames.length; + const text = + spaceCount === 1 + ? i18n.translate( + 'xpack.spaces.management.shareToSpace.shareRemoveSuccessTextSingular', + { + defaultMessage: `'{object}' was removed from 1 space.`, + values: { object: meta.title }, + } + ) + : i18n.translate('xpack.spaces.management.shareToSpace.shareRemoveSuccessTextPlural', { + defaultMessage: `'{object}' was removed from {spaceCount} spaces.`, + values: { object: meta.title, spaceCount }, + }); toastNotifications.addSuccess({ title, text }); } onObjectUpdated(); @@ -210,7 +227,7 @@ export const ShareSavedObjectsToSpaceFlyout = (props: Props) => {

diff --git a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/share_to_space_form.tsx b/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/share_to_space_form.tsx index 24402fec8d77..ad84ea85d5e5 100644 --- a/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/share_to_space_form.tsx +++ b/x-pack/plugins/spaces/public/share_saved_objects_to_space/components/share_to_space_form.tsx @@ -35,14 +35,14 @@ export const ShareToSpaceForm = (props: Props) => { title={ } color="warning" > { label={ } labelAppend={ diff --git a/x-pack/plugins/spaces/public/share_saved_objects_to_space/share_saved_objects_to_space_column.tsx b/x-pack/plugins/spaces/public/share_saved_objects_to_space/share_saved_objects_to_space_column.tsx index e8649faa120b..93d7bb017051 100644 --- a/x-pack/plugins/spaces/public/share_saved_objects_to_space/share_saved_objects_to_space_column.tsx +++ b/x-pack/plugins/spaces/public/share_saved_objects_to_space/share_saved_objects_to_space_column.tsx @@ -52,7 +52,7 @@ const ColumnDisplay = ({ namespaces, data }: ColumnDataProps) => { const unauthorizedCount = (namespaces?.filter((namespace) => namespace === '?') ?? []).length; const unauthorizedTooltip = i18n.translate( 'xpack.spaces.management.shareToSpace.columnUnauthorizedLabel', - { defaultMessage: 'You do not have permission to view these spaces' } + { defaultMessage: `You don't have permission to view these spaces.` } ); const displayedSpaces = isExpanded diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 2435d8a9aaf0..904b14a7459a 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -51,6 +51,27 @@ } } }, + "enterprise_search": { + "properties": { + "ui_viewed": { + "properties": { + "overview": { + "type": "long" + } + } + }, + "ui_clicked": { + "properties": { + "app_search": { + "type": "long" + }, + "workplace_search": { + "type": "long" + } + } + } + } + }, "workplace_search": { "properties": { "ui_viewed": { @@ -276,6 +297,28 @@ } } }, + "security": { + "properties": { + "auditLoggingEnabled": { + "type": "boolean" + }, + "loginSelectorEnabled": { + "type": "boolean" + }, + "accessAgreementEnabled": { + "type": "boolean" + }, + "authProviderCount": { + "type": "number" + }, + "enabledAuthProviders": { + "type": "keyword" + }, + "httpAuthSchemes": { + "type": "keyword" + } + } + }, "spaces": { "properties": { "usesFeatureControls": { diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx index cf32bf0455a1..dad0f0e5ee28 100644 --- a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_list.tsx @@ -4,31 +4,30 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { MouseEventHandler, FC, useContext, useState } from 'react'; +import React, { MouseEventHandler, FC, useContext, useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { - Direction, - EuiBadge, + EuiBasicTable, + EuiBasicTableProps, EuiButtonEmpty, EuiButtonIcon, EuiCallOut, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem, - EuiInMemoryTable, - EuiSearchBarProps, + EuiSearchBar, + EuiSpacer, EuiPopover, EuiTitle, } from '@elastic/eui'; -import { TransformId, TRANSFORM_STATE } from '../../../../../../common'; +import { TransformId } from '../../../../../../common'; import { useRefreshTransformList, TransformListRow, - TRANSFORM_MODE, TRANSFORM_LIST_COLUMN, } from '../../../../common'; import { useStopTransforms } from '../../../../hooks'; @@ -45,9 +44,11 @@ import { import { useStartAction, StartActionName, StartActionModal } from '../action_start'; import { StopActionName } from '../action_stop'; -import { ItemIdToExpandedRowMap, Clause, TermClause, FieldClause, Value } from './common'; -import { getTaskStateBadge, useColumns } from './use_columns'; +import { ItemIdToExpandedRowMap } from './common'; +import { useColumns } from './use_columns'; import { ExpandedRow } from './expanded_row'; +import { TransformSearchBar, filterTransforms } from './transform_search_bar'; +import { useTableSettings } from './use_table_settings'; function getItemIdToExpandedRowMap( itemIds: TransformId[], @@ -62,14 +63,6 @@ function getItemIdToExpandedRowMap( }, {} as ItemIdToExpandedRowMap); } -function stringMatch(str: string | undefined, substr: any) { - return ( - typeof str === 'string' && - typeof substr === 'string' && - (str.toLowerCase().match(substr.toLowerCase()) === null) === false - ); -} - interface Props { errorMessage: any; isInitialized: boolean; @@ -88,24 +81,14 @@ export const TransformList: FC = ({ const [isLoading, setIsLoading] = useState(false); const { refresh } = useRefreshTransformList({ isLoading: setIsLoading }); - const [filterActive, setFilterActive] = useState(false); - + const [searchQueryText, setSearchQueryText] = useState(''); const [filteredTransforms, setFilteredTransforms] = useState([]); const [expandedRowItemIds, setExpandedRowItemIds] = useState([]); - const [transformSelection, setTransformSelection] = useState([]); const [isActionsMenuOpen, setIsActionsMenuOpen] = useState(false); const bulkStartAction = useStartAction(false); const bulkDeleteAction = useDeleteAction(false); - const [searchError, setSearchError] = useState(undefined); - - const [pageIndex, setPageIndex] = useState(0); - const [pageSize, setPageSize] = useState(10); - - const [sortField, setSortField] = useState(TRANSFORM_LIST_COLUMN.ID); - const [sortDirection, setSortDirection] = useState('asc'); - const stopTransforms = useStopTransforms(); const { capabilities } = useContext(AuthorizationContext); @@ -114,90 +97,41 @@ export const TransformList: FC = ({ !capabilities.canPreviewTransform || !capabilities.canStartStopTransform; - const onQueryChange = ({ - query, - error, - }: Parameters>[0]) => { - if (error) { - setSearchError(error.message); + const { columns, modals: singleActionModals } = useColumns( + expandedRowItemIds, + setExpandedRowItemIds, + transformSelection + ); + + const updateFilteredItems = (queryClauses: any) => { + if (queryClauses.length) { + const filtered = filterTransforms(transforms, queryClauses); + setFilteredTransforms(filtered); } else { - let clauses: Clause[] = []; - if (query && query.ast !== undefined && query.ast.clauses !== undefined) { - clauses = query.ast.clauses; - } - if (clauses.length > 0) { - setFilterActive(true); - filterTransforms(clauses as Array); - } else { - setFilterActive(false); - } - setSearchError(undefined); + setFilteredTransforms(transforms); } }; - const filterTransforms = (clauses: Array) => { - setIsLoading(true); - // keep count of the number of matches we make as we're looping over the clauses - // we only want to return transforms which match all clauses, i.e. each search term is ANDed - // { transform-one: { transform: { id: transform-one, config: {}, state: {}, ... }, count: 0 }, transform-two: {...} } - const matches: Record = transforms.reduce((p: Record, c) => { - p[c.id] = { - transform: c, - count: 0, - }; - return p; - }, {}); - - clauses.forEach((c) => { - // the search term could be negated with a minus, e.g. -bananas - const bool = c.match === 'must'; - let ts = []; - - if (c.type === 'term') { - // filter term based clauses, e.g. bananas - // match on ID and description - // if the term has been negated, AND the matches - if (bool === true) { - ts = transforms.filter( - (transform) => - stringMatch(transform.id, c.value) === bool || - stringMatch(transform.config.description, c.value) === bool - ); - } else { - ts = transforms.filter( - (transform) => - stringMatch(transform.id, c.value) === bool && - stringMatch(transform.config.description, c.value) === bool - ); + useEffect(() => { + const filterList = () => { + if (searchQueryText !== '') { + const query = EuiSearchBar.Query.parse(searchQueryText); + let clauses: any = []; + if (query && query.ast !== undefined && query.ast.clauses !== undefined) { + clauses = query.ast.clauses; } + updateFilteredItems(clauses); } else { - // filter other clauses, i.e. the mode and status filters - if (Array.isArray(c.value)) { - // the status value is an array of string(s) e.g. ['failed', 'stopped'] - ts = transforms.filter((transform) => - (c.value as Value[]).includes(transform.stats.state) - ); - } else { - ts = transforms.filter((transform) => transform.mode === c.value); - } + updateFilteredItems([]); } - - ts.forEach((t) => matches[t.id].count++); - }); - - // loop through the matches and return only transforms which have match all the clauses - const filtered = Object.values(matches) - .filter((m) => (m && m.count) >= clauses.length) - .map((m) => m.transform); - - setFilteredTransforms(filtered); - setIsLoading(false); - }; - - const { columns, modals: singleActionModals } = useColumns( - expandedRowItemIds, - setExpandedRowItemIds, - transformSelection + }; + filterList(); + // eslint-disable-next-line + }, [searchQueryText, transforms]); // missing dependency updateFilteredItems + + const { onTableChange, pageOfItems, pagination, sorting } = useTableSettings( + TRANSFORM_LIST_COLUMN.ID, + filteredTransforms ); // Before the transforms have been loaded for the first time, display the loading indicator only. @@ -246,23 +180,8 @@ export const TransformList: FC = ({ ); } - const sorting = { - sort: { - field: sortField, - direction: sortDirection, - }, - }; - const itemIdToExpandedRowMap = getItemIdToExpandedRowMap(expandedRowItemIds, transforms); - const pagination = { - initialPageIndex: pageIndex, - initialPageSize: pageSize, - totalItemCount: transforms.length, - pageSizeOptions: [10, 20, 50], - hidePerPageOptions: false, - }; - const bulkActionMenuItems = [
bulkStartAction.openModal(transformSelection)}> @@ -331,7 +250,7 @@ export const TransformList: FC = ({ ]; }; - const renderToolsRight = () => ( + const toolsRight = ( @@ -342,56 +261,6 @@ export const TransformList: FC = ({ ); - const search = { - toolsLeft: transformSelection.length > 0 ? renderToolsLeft() : undefined, - toolsRight: renderToolsRight(), - onChange: onQueryChange, - box: { - incremental: true, - }, - filters: [ - { - type: 'field_value_selection' as const, - field: 'state.state', - name: i18n.translate('xpack.transform.statusFilter', { defaultMessage: 'Status' }), - multiSelect: 'or' as const, - options: Object.values(TRANSFORM_STATE).map((val) => ({ - value: val, - name: val, - view: getTaskStateBadge(val), - })), - }, - { - type: 'field_value_selection' as const, - field: 'mode', - name: i18n.translate('xpack.transform.modeFilter', { defaultMessage: 'Mode' }), - multiSelect: false, - options: Object.values(TRANSFORM_MODE).map((val) => ({ - value: val, - name: val, - view: ( - - {val} - - ), - })), - }, - ], - }; - - const onTableChange = ({ - page = { index: 0, size: 10 }, - sort = { field: TRANSFORM_LIST_COLUMN.ID as string, direction: 'asc' }, - }) => { - const { index, size } = page; - setPageIndex(index); - setPageSize(size); - - const { field, direction } = sort; - setSortField(field as string); - setSortDirection(direction as Direction); - }; - const selection = { onSelectionChange: (selected: TransformListRow[]) => setTransformSelection(selected), }; @@ -404,30 +273,38 @@ export const TransformList: FC = ({ {/* Single Action Modals */} {singleActionModals} - - + {transformSelection.length > 0 ? ( + {renderToolsLeft()} + ) : null} + + + + {toolsRight} + + + columns={columns} - error={searchError} hasActions={false} isExpandable={true} isSelectable={false} - items={filterActive ? filteredTransforms : transforms} + items={pageOfItems as TransformListRow[]} itemId={TRANSFORM_LIST_COLUMN.ID} itemIdToExpandedRowMap={itemIdToExpandedRowMap} loading={isLoading || transformsLoading} - onTableChange={onTableChange} - pagination={pagination} - rowProps={(item) => ({ - 'data-test-subj': `transformListRow row-${item.id}`, - })} + onChange={onTableChange as EuiBasicTableProps['onChange']} selection={selection} + pagination={pagination!} sorting={sorting} - search={search} data-test-subj={`transformListTable ${ isLoading || transformsLoading ? 'loading' : 'loaded' }`} + rowProps={(item) => ({ + 'data-test-subj': `transformListRow row-${item.id}`, + })} />
); diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_search_bar.tsx b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_search_bar.tsx new file mode 100644 index 000000000000..fab591f88131 --- /dev/null +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/transform_search_bar.tsx @@ -0,0 +1,181 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { Dispatch, SetStateAction, FC, Fragment, useState } from 'react'; +import { + EuiBadge, + EuiSearchBar, + EuiSearchBarProps, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + SearchFilterConfig, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { TermClause, FieldClause, Value } from './common'; +import { TRANSFORM_STATE } from '../../../../../../common'; +import { TRANSFORM_MODE, TransformListRow } from '../../../../common'; +import { getTaskStateBadge } from './use_columns'; + +const filters: SearchFilterConfig[] = [ + { + type: 'field_value_selection', + field: 'state.state', + name: i18n.translate('xpack.transform.statusFilter', { defaultMessage: 'Status' }), + multiSelect: 'or', + options: Object.values(TRANSFORM_STATE).map((val) => ({ + value: val, + name: val, + view: getTaskStateBadge(val), + })), + }, + { + type: 'field_value_selection', + field: 'mode', + name: i18n.translate('xpack.transform.modeFilter', { defaultMessage: 'Mode' }), + multiSelect: false, + options: Object.values(TRANSFORM_MODE).map((val) => ({ + value: val, + name: val, + view: ( + + {val} + + ), + })), + }, +]; + +function stringMatch(str: string | undefined, substr: any) { + return ( + typeof str === 'string' && + typeof substr === 'string' && + (str.toLowerCase().match(substr.toLowerCase()) === null) === false + ); +} + +export const filterTransforms = ( + transforms: TransformListRow[], + clauses: Array +) => { + // keep count of the number of matches we make as we're looping over the clauses + // we only want to return transforms which match all clauses, i.e. each search term is ANDed + // { transform-one: { transform: { id: transform-one, config: {}, state: {}, ... }, count: 0 }, transform-two: {...} } + const matches: Record = transforms.reduce((p: Record, c) => { + p[c.id] = { + transform: c, + count: 0, + }; + return p; + }, {}); + + clauses.forEach((c) => { + // the search term could be negated with a minus, e.g. -bananas + const bool = c.match === 'must'; + let ts = []; + + if (c.type === 'term') { + // filter term based clauses, e.g. bananas + // match on ID and description + // if the term has been negated, AND the matches + if (bool === true) { + ts = transforms.filter( + (transform) => + stringMatch(transform.id, c.value) === bool || + stringMatch(transform.config.description, c.value) === bool + ); + } else { + ts = transforms.filter( + (transform) => + stringMatch(transform.id, c.value) === bool && + stringMatch(transform.config.description, c.value) === bool + ); + } + } else { + // filter other clauses, i.e. the mode and status filters + if (Array.isArray(c.value)) { + // the status value is an array of string(s) e.g. ['failed', 'stopped'] + ts = transforms.filter((transform) => (c.value as Value[]).includes(transform.stats.state)); + } else { + ts = transforms.filter((transform) => transform.mode === c.value); + } + } + + ts.forEach((t) => matches[t.id].count++); + }); + + // loop through the matches and return only transforms which have match all the clauses + const filtered = Object.values(matches) + .filter((m) => (m && m.count) >= clauses.length) + .map((m) => m.transform); + + return filtered; +}; + +function getError(errorMessage: string | null) { + if (errorMessage) { + return i18n.translate('xpack.transform.transformList.searchBar.invalidSearchErrorMessage', { + defaultMessage: 'Invalid search: {errorMessage}', + values: { errorMessage }, + }); + } + + return ''; +} + +interface Props { + searchQueryText: string; + setSearchQueryText: Dispatch>; +} + +export const TransformSearchBar: FC = ({ searchQueryText, setSearchQueryText }) => { + const [errorMessage, setErrorMessage] = useState(null); + + const onChange: EuiSearchBarProps['onChange'] = ({ query, error }) => { + if (error) { + setErrorMessage(error.message); + } else if (query !== null && query.text !== undefined) { + setSearchQueryText(query.text); + setErrorMessage(null); + } + }; + + return ( + + + {searchQueryText === undefined && ( + + )} + {searchQueryText !== undefined && ( + + )} + + + + + + ); +}; diff --git a/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_table_settings.ts b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_table_settings.ts new file mode 100644 index 000000000000..ad40a3f8103b --- /dev/null +++ b/x-pack/plugins/transform/public/app/sections/transform_management/components/transform_list/use_table_settings.ts @@ -0,0 +1,135 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useState } from 'react'; +import { Direction, EuiBasicTableProps, EuiTableSortingType } from '@elastic/eui'; +import sortBy from 'lodash/sortBy'; +import get from 'lodash/get'; + +const PAGE_SIZE = 10; +const PAGE_SIZE_OPTIONS = [10, 25, 50]; + +const propertyMap = { + Mode: 'mode', +}; + +// Copying from EUI EuiBasicTable types as type is not correctly picked up for table's onChange +// Can be removed when https://github.com/elastic/eui/issues/4011 is addressed in EUI +export interface Criteria { + page?: { + index: number; + size: number; + }; + sort?: { + field: keyof T; + direction: Direction; + }; +} +export interface CriteriaWithPagination extends Criteria { + page: { + index: number; + size: number; + }; +} + +interface AnalyticsBasicTableSettings { + pageIndex: number; + pageSize: number; + totalItemCount: number; + hidePerPageOptions: boolean; + sortField: keyof T; + sortDirection: Direction; +} + +interface UseTableSettingsReturnValue { + onTableChange: EuiBasicTableProps['onChange']; + pageOfItems: T[]; + pagination: EuiBasicTableProps['pagination']; + sorting: EuiTableSortingType; +} + +export function useTableSettings( + sortByField: keyof TypeOfItem, + items: TypeOfItem[] +): UseTableSettingsReturnValue { + const [tableSettings, setTableSettings] = useState>({ + pageIndex: 0, + pageSize: PAGE_SIZE, + totalItemCount: 0, + hidePerPageOptions: false, + sortField: sortByField, + sortDirection: 'asc', + }); + + const getPageOfItems = ( + list: TypeOfItem[], + index: number, + size: number, + sortField: keyof TypeOfItem, + sortDirection: Direction + ) => { + list = sortBy(list, (item) => + get(item, propertyMap[sortField as keyof typeof propertyMap] || sortField) + ); + list = sortDirection === 'asc' ? list : list.reverse(); + const listLength = list.length; + + let pageStart = index * size; + if (pageStart >= listLength && listLength !== 0) { + // if the page start is larger than the number of items due to + // filters being applied or items being deleted, calculate a new page start + pageStart = Math.floor((listLength - 1) / size) * size; + + setTableSettings({ ...tableSettings, pageIndex: pageStart / size }); + } + return { + pageOfItems: list.slice(pageStart, pageStart + size), + totalItemCount: listLength, + }; + }; + + const onTableChange: EuiBasicTableProps['onChange'] = ({ + page = { index: 0, size: PAGE_SIZE }, + sort = { field: sortByField, direction: 'asc' }, + }: CriteriaWithPagination) => { + const { index, size } = page; + const { field, direction } = sort; + + setTableSettings({ + ...tableSettings, + pageIndex: index, + pageSize: size, + sortField: field, + sortDirection: direction, + }); + }; + + const { pageIndex, pageSize, sortField, sortDirection } = tableSettings; + + const { pageOfItems, totalItemCount } = getPageOfItems( + items, + pageIndex, + pageSize, + sortField, + sortDirection + ); + + const pagination = { + pageIndex, + pageSize, + totalItemCount, + pageSizeOptions: PAGE_SIZE_OPTIONS, + }; + + const sorting = { + sort: { + field: sortField, + direction: sortDirection, + }, + }; + + return { onTableChange, pageOfItems, pagination, sorting }; +} diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index eacb1febd20f..54c92d323fcf 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -2880,7 +2880,6 @@ "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsDescription": "影響されるオブジェクトのサンプル", "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsName": "影響されるオブジェクトのサンプル", "savedObjectsManagement.objectsTable.flyout.resolveImportErrorsFileErrorMessage": "ファイルを処理できませんでした。", - "savedObjectsManagement.objectsTable.flyout.selectFileToImportFormRowLabel": "インポートするファイルを選択してください", "savedObjectsManagement.objectsTable.header.exportButtonLabel": "{filteredCount, plural, one{# オブジェクト} other {# オブジェクト}}をエクスポート", "savedObjectsManagement.objectsTable.header.importButtonLabel": "インポート", "savedObjectsManagement.objectsTable.header.refreshButtonLabel": "更新", @@ -4446,7 +4445,6 @@ "xpack.actions.builtin.case.connectorApiNullError": "コネクター[apiUrl]が必要です", "xpack.actions.builtin.case.jiraTitle": "Jira", "xpack.actions.builtin.case.resilientTitle": "IBM Resilient", - "xpack.actions.builtin.configuration.apiWhitelistError": "コネクターアクションの構成エラー:{message}", "xpack.actions.builtin.email.errorSendingErrorMessage": "エラー送信メールアドレス", "xpack.actions.builtin.emailTitle": "メール", "xpack.actions.builtin.esIndex.errorIndexingErrorMessage": "エラーインデックス作成ドキュメント", @@ -9643,9 +9641,7 @@ "xpack.lens.indexPattern.fieldTopValuesLabel": "トップの値", "xpack.lens.indexPattern.groupByDropdown": "グループ分けの条件", "xpack.lens.indexPattern.groupingControlLabel": "グループ分け", - "xpack.lens.indexPattern.groupingOverallDateHistogram": "全体の日付", "xpack.lens.indexPattern.groupingOverallTerms": "全体のトップ {field}", - "xpack.lens.indexPattern.groupingSecondDateHistogram": "各 {target} の日付", "xpack.lens.indexPattern.groupingSecondTerms": "各 {target} のトップの値", "xpack.lens.indexPattern.indexPatternLoadError": "インデックスパターンの読み込み中にエラーが発生", "xpack.lens.indexPattern.invalidInterval": "無効な間隔値", @@ -14083,8 +14079,6 @@ "xpack.reporting.screencapture.waitingForRenderComplete": "レンダリングの完了を待っています", "xpack.reporting.screencapture.waitingForRenderedElements": "レンダリングされた {itemsCount} 個の要素が DOM に入るのを待っています", "xpack.reporting.screenCapturePanelContent.optimizeForPrintingLabel": "印刷用に最適化", - "xpack.reporting.selfCheck.ok": "レポートプラグイン自己チェックOK!", - "xpack.reporting.selfCheck.warning": "レポートプラグイン自己チェックで警告が発生しました: {err}", "xpack.reporting.serverConfig.autoSet.sandboxDisabled": "Chromiumサンドボックスは保護が強化されていますが、{osName} OSではサポートされていません。自動的に'{configKey}: true'を設定しています。", "xpack.reporting.serverConfig.autoSet.sandboxEnabled": "Chromiumサンドボックスは保護が強化され、{osName} OSでサポートされています。自動的にChromiumサンドボックスを有効にしています。", "xpack.reporting.serverConfig.invalidServerHostname": "Kibana構成で「server.host:\"0\"」が見つかりました。これはReportingと互換性がありません。レポートが動作するように、「{configKey}:0.0.0.0」が自動的に構成になります。設定を「server.host:0.0.0.0」に変更するか、kibana.ymlに「{configKey}:0.0.0.0'」を追加して、このメッセージが表示されないようにすることができます。", @@ -15117,7 +15111,6 @@ "xpack.securitySolution.case.configureCases.mappingFieldDescription": "説明", "xpack.securitySolution.case.configureCases.mappingFieldName": "名前", "xpack.securitySolution.case.configureCases.mappingFieldNotMapped": "マップされません", - "xpack.securitySolution.case.configureCases.mappingFieldSummary": "まとめ", "xpack.securitySolution.case.configureCases.noConnector": "コネクターを選択していません", "xpack.securitySolution.case.configureCases.updateConnector": "コネクターを更新", "xpack.securitySolution.case.configureCases.updateSelectedConnector": "{ connectorName }を更新", @@ -15141,14 +15134,6 @@ "xpack.securitySolution.case.connectors.common.requiredPasswordTextField": "パスワードが必要です", "xpack.securitySolution.case.connectors.common.requiredUsernameTextField": "ユーザー名が必要です", "xpack.securitySolution.case.connectors.common.usernameTextFieldLabel": "ユーザー名", - "xpack.securitySolution.case.connectors.jira.actionTypeTitle": "Jira", - "xpack.securitySolution.case.connectors.jira.apiTokenTextFieldLabel": "APIトークンまたはパスワード", - "xpack.securitySolution.case.connectors.jira.emailTextFieldLabel": "電子メールアドレスまたはユーザー名", - "xpack.securitySolution.case.connectors.jira.projectKey": "プロジェクトキー", - "xpack.securitySolution.case.connectors.jira.requiredApiTokenTextField": "APIトークンまたはパスワードが必要です", - "xpack.securitySolution.case.connectors.jira.requiredEmailTextField": "電子メールアドレスまたはユーザー名が必要です", - "xpack.securitySolution.case.connectors.jira.requiredProjectKeyTextField": "プロジェクトキーが必要です", - "xpack.securitySolution.case.connectors.jira.selectMessageText": "Jiraでセキュリティケースデータを更新するか、新しいインシデントにプッシュ", "xpack.securitySolution.case.connectors.resilient.actionTypeTitle": "IBM Resilient", "xpack.securitySolution.case.connectors.resilient.apiKeyId": "APIキーID", "xpack.securitySolution.case.connectors.resilient.apiKeySecret": "APIキーシークレット", @@ -17602,8 +17587,6 @@ "xpack.spaces.management.copyToSpace.actionTitle": "スペースにコピー", "xpack.spaces.management.copyToSpace.copyErrorTitle": "保存されたオブジェクトのコピー中にエラーが発生", "xpack.spaces.management.copyToSpace.copyResultsLabel": "コピー結果", - "xpack.spaces.management.copyToSpace.copyStatus.conflictsMessage": "このスペースには同じID({id})の保存されたオブジェクトが既に存在します。", - "xpack.spaces.management.copyToSpace.copyStatus.conflictsOverwriteMessage": "「上書き」をクリックしてこのバージョンをコピーされたバージョンに置き換えます。", "xpack.spaces.management.copyToSpace.copyStatus.pendingOverwriteMessage": "保存されたオブジェクトは上書きされます。「スキップ」をクリックしてこの操作をキャンセルします。", "xpack.spaces.management.copyToSpace.copyStatus.successMessage": "保存されたオブジェクトがコピーされました。", "xpack.spaces.management.copyToSpace.copyStatus.unresolvableErrorMessage": "この保存されたオブジェクトのコピー中にエラーが発生しました。", @@ -17612,8 +17595,6 @@ "xpack.spaces.management.copyToSpace.copyStatusSummary.successMessage": "{space}スペースにコピーされました。", "xpack.spaces.management.copyToSpace.copyToSpacesButton": "{spaceCount} {spaceCount, plural, one {スペース} other {スペース}}にコピー", "xpack.spaces.management.copyToSpace.disabledCopyToSpacesButton": "コピー", - "xpack.spaces.management.copyToSpace.dontIncludeRelatedLabel": "関連性のある保存されたオブジェクトを含みません", - "xpack.spaces.management.copyToSpace.dontOverwriteLabel": "保存されたオブジェクトを上書きしません", "xpack.spaces.management.copyToSpace.finishCopyToSpacesButton": "終了", "xpack.spaces.management.copyToSpace.finishedButtonLabel": "コピーが完了しました。", "xpack.spaces.management.copyToSpace.finishPendingOverwritesCopyToSpacesButton": "{overwriteCount}件のオブジェクトを上書き", @@ -17621,10 +17602,8 @@ "xpack.spaces.management.copyToSpace.inProgressButtonLabel": "コピーが進行中です。お待ちください。", "xpack.spaces.management.copyToSpace.noSpacesBody": "コピーできるスペースがありません。", "xpack.spaces.management.copyToSpace.noSpacesTitle": "スペースがありません", - "xpack.spaces.management.copyToSpace.overwriteLabel": "保存されたオブジェクトを自動的に上書きしています", "xpack.spaces.management.copyToSpace.resolveCopyErrorTitle": "保存されたオブジェクトの矛盾の解決中にエラーが発生", "xpack.spaces.management.copyToSpace.resolveCopySuccessTitle": "上書き成功", - "xpack.spaces.management.copyToSpace.selectSpacesLabel": "コピー先のスペースを選択してください", "xpack.spaces.management.copyToSpace.spacesLoadErrorTitle": "利用可能なスペースを読み込み中にエラーが発生", "xpack.spaces.management.copyToSpaceFlyoutFooter.errorCount": "エラー", "xpack.spaces.management.copyToSpaceFlyoutFooter.pendingCount": "保留中", @@ -17703,7 +17682,6 @@ "xpack.spaces.management.spacesGridPage.spacesTitle": "スペース", "xpack.spaces.management.spacesGridPage.spaceSuccessfullyDeletedNotificationMessage": "「{spaceName}」 スペースが削除されました。", "xpack.spaces.management.toggleAllFeaturesLink": "(すべて変更)", - "xpack.spaces.management.unauthorizedPrompt.permissionDeniedDescription": "スペースを管理するパーミッションがありません。", "xpack.spaces.management.unauthorizedPrompt.permissionDeniedTitle": "パーミッションが拒否されました", "xpack.spaces.management.validateSpace.describeMaxLengthErrorMessage": "説明は 2000 文字以内でなければなりません。", "xpack.spaces.management.validateSpace.nameMaxLengthErrorMessage": "名前はは 1024 文字以内でなければなりません。", @@ -18253,7 +18231,6 @@ "xpack.triggersActionsUI.sections.alertDetails.collapsedItemActons.muteTitle": "ミュート", "xpack.triggersActionsUI.sections.alertDetails.editAlertButtonLabel": "編集", "xpack.triggersActionsUI.sections.alertDetails.unableToLoadAlertMessage": "アラートを読み込めません: {message}", - "xpack.triggersActionsUI.sections.alertDetails.unableToLoadAlertStateMessage": "アラートステートを読み込めません: {message}", "xpack.triggersActionsUI.sections.alertDetails.viewAlertInAppButtonLabel": "アプリで表示", "xpack.triggersActionsUI.sections.alertEdit.betaBadgeTooltipContent": "{pluginName} はベータ段階で、変更される可能性があります。デザインとコードはオフィシャル GA 機能よりも完成度が低く、現状のまま保証なしで提供されています。ベータ機能にはオフィシャル GA 機能の SLA が適用されません。", "xpack.triggersActionsUI.sections.alertEdit.cancelButtonLabel": "キャンセル", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index bd30703dd5bd..df721cb62466 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2881,7 +2881,6 @@ "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsDescription": "受影响对象样例", "savedObjectsManagement.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsName": "受影响对象样例", "savedObjectsManagement.objectsTable.flyout.resolveImportErrorsFileErrorMessage": "无法处理该文件。", - "savedObjectsManagement.objectsTable.flyout.selectFileToImportFormRowLabel": "请选择要导入的文件", "savedObjectsManagement.objectsTable.header.exportButtonLabel": "导出 {filteredCount, plural, one{# 个对象} other {# 个对象}}", "savedObjectsManagement.objectsTable.header.importButtonLabel": "导入", "savedObjectsManagement.objectsTable.header.refreshButtonLabel": "刷新", @@ -4447,7 +4446,6 @@ "xpack.actions.builtin.case.connectorApiNullError": "需要指定连接器 [apiUrl]", "xpack.actions.builtin.case.jiraTitle": "Jira", "xpack.actions.builtin.case.resilientTitle": "IBM Resilient", - "xpack.actions.builtin.configuration.apiWhitelistError": "配置连接器操作时出错:{message}", "xpack.actions.builtin.email.errorSendingErrorMessage": "发送电子邮件时出错", "xpack.actions.builtin.emailTitle": "电子邮件", "xpack.actions.builtin.esIndex.errorIndexingErrorMessage": "索引文档时出错", @@ -9649,9 +9647,7 @@ "xpack.lens.indexPattern.fieldTopValuesLabel": "排名最前值", "xpack.lens.indexPattern.groupByDropdown": "分组依据", "xpack.lens.indexPattern.groupingControlLabel": "分组", - "xpack.lens.indexPattern.groupingOverallDateHistogram": "日期 - 总体", "xpack.lens.indexPattern.groupingOverallTerms": "总体排名最前 {field}", - "xpack.lens.indexPattern.groupingSecondDateHistogram": "每个 {target} 的日期", "xpack.lens.indexPattern.groupingSecondTerms": "每个 {target} 的排名最前值", "xpack.lens.indexPattern.indexPatternLoadError": "加载索引模式时出错", "xpack.lens.indexPattern.invalidInterval": "时间间隔值无效", @@ -14092,8 +14088,6 @@ "xpack.reporting.screencapture.waitingForRenderComplete": "正在等候渲染完成", "xpack.reporting.screencapture.waitingForRenderedElements": "正在等候 {itemsCount} 个已渲染元素进入 DOM", "xpack.reporting.screenCapturePanelContent.optimizeForPrintingLabel": "打印优化", - "xpack.reporting.selfCheck.ok": "Reporting 插件自检正常!", - "xpack.reporting.selfCheck.warning": "Reporting 插件自检生成警告:{err}", "xpack.reporting.serverConfig.autoSet.sandboxDisabled": "Chromium 沙盒提供附加保护层,但不受 {osName} OS 支持。自动设置“{configKey}: true”。", "xpack.reporting.serverConfig.autoSet.sandboxEnabled": "Chromium 沙盒提供附加保护层,受 {osName} OS 支持。自动启用 Chromium 沙盒。", "xpack.reporting.serverConfig.invalidServerHostname": "在 Kibana 配置中找到“server.host:\"0\"”。其不与 Reporting 兼容。要使 Reporting 运行,“{configKey}:0.0.0.0”将自动添加到配置中。可以将该设置更改为“server.host:0.0.0.0”或在 kibana.yml 中添加“{configKey}:0.0.0.0”,以阻止此消息。", @@ -15126,7 +15120,6 @@ "xpack.securitySolution.case.configureCases.mappingFieldDescription": "描述", "xpack.securitySolution.case.configureCases.mappingFieldName": "名称", "xpack.securitySolution.case.configureCases.mappingFieldNotMapped": "未映射", - "xpack.securitySolution.case.configureCases.mappingFieldSummary": "摘要", "xpack.securitySolution.case.configureCases.noConnector": "未选择连接器", "xpack.securitySolution.case.configureCases.updateConnector": "更新连接器", "xpack.securitySolution.case.configureCases.updateSelectedConnector": "更新 { connectorName }", @@ -15150,14 +15143,6 @@ "xpack.securitySolution.case.connectors.common.requiredPasswordTextField": "“密码”必填", "xpack.securitySolution.case.connectors.common.requiredUsernameTextField": "“用户名”必填", "xpack.securitySolution.case.connectors.common.usernameTextFieldLabel": "用户名", - "xpack.securitySolution.case.connectors.jira.actionTypeTitle": "Jira", - "xpack.securitySolution.case.connectors.jira.apiTokenTextFieldLabel": "API 令牌或密码", - "xpack.securitySolution.case.connectors.jira.emailTextFieldLabel": "电子邮件或用户名", - "xpack.securitySolution.case.connectors.jira.projectKey": "项目键", - "xpack.securitySolution.case.connectors.jira.requiredApiTokenTextField": "“API 令牌或密码”必填", - "xpack.securitySolution.case.connectors.jira.requiredEmailTextField": "“电子邮件或用户名”必填", - "xpack.securitySolution.case.connectors.jira.requiredProjectKeyTextField": "“项目键”必填", - "xpack.securitySolution.case.connectors.jira.selectMessageText": "将 Security 案例数据推送或更新到 Jira 中的新问题", "xpack.securitySolution.case.connectors.resilient.actionTypeTitle": "IBM Resilient", "xpack.securitySolution.case.connectors.resilient.apiKeyId": "API 密钥 ID", "xpack.securitySolution.case.connectors.resilient.apiKeySecret": "API 密钥密码", @@ -17612,8 +17597,6 @@ "xpack.spaces.management.copyToSpace.actionTitle": "复制到工作区", "xpack.spaces.management.copyToSpace.copyErrorTitle": "复制已保存对象时出错", "xpack.spaces.management.copyToSpace.copyResultsLabel": "复制结果", - "xpack.spaces.management.copyToSpace.copyStatus.conflictsMessage": "具有匹配 ID ({id}) 的已保存对象在此工作区中已存在。", - "xpack.spaces.management.copyToSpace.copyStatus.conflictsOverwriteMessage": "单击“覆盖”可将此版本替换为复制的版本。", "xpack.spaces.management.copyToSpace.copyStatus.pendingOverwriteMessage": "已保存对象将被覆盖。单击“跳过”可取消此操作。", "xpack.spaces.management.copyToSpace.copyStatus.successMessage": "已保存对象成功复制。", "xpack.spaces.management.copyToSpace.copyStatus.unresolvableErrorMessage": "复制此已保存对象时出错。", @@ -17622,8 +17605,6 @@ "xpack.spaces.management.copyToSpace.copyStatusSummary.successMessage": "已成功复制到 {space} 工作区。", "xpack.spaces.management.copyToSpace.copyToSpacesButton": "复制到 {spaceCount} {spaceCount, plural, one {个工作区} other {个工作区}}", "xpack.spaces.management.copyToSpace.disabledCopyToSpacesButton": "复制", - "xpack.spaces.management.copyToSpace.dontIncludeRelatedLabel": "不包括相关已保存对象", - "xpack.spaces.management.copyToSpace.dontOverwriteLabel": "未覆盖已保存对象", "xpack.spaces.management.copyToSpace.finishCopyToSpacesButton": "完成", "xpack.spaces.management.copyToSpace.finishedButtonLabel": "复制已完成。", "xpack.spaces.management.copyToSpace.finishPendingOverwritesCopyToSpacesButton": "覆盖 {overwriteCount} 个对象", @@ -17631,10 +17612,8 @@ "xpack.spaces.management.copyToSpace.inProgressButtonLabel": "复制正在进行中。请稍候。", "xpack.spaces.management.copyToSpace.noSpacesBody": "没有可向其中进行复制的合格工作区。", "xpack.spaces.management.copyToSpace.noSpacesTitle": "没有可用的工作区", - "xpack.spaces.management.copyToSpace.overwriteLabel": "正在自动覆盖已保存对象", "xpack.spaces.management.copyToSpace.resolveCopyErrorTitle": "解决已保存对象冲突时出错", "xpack.spaces.management.copyToSpace.resolveCopySuccessTitle": "覆盖成功", - "xpack.spaces.management.copyToSpace.selectSpacesLabel": "选择要向其中进行复制的工作区", "xpack.spaces.management.copyToSpace.spacesLoadErrorTitle": "加载可用工作区时出错", "xpack.spaces.management.copyToSpaceFlyoutFooter.errorCount": "错误", "xpack.spaces.management.copyToSpaceFlyoutFooter.pendingCount": "待处理", @@ -17713,7 +17692,6 @@ "xpack.spaces.management.spacesGridPage.spacesTitle": "工作区", "xpack.spaces.management.spacesGridPage.spaceSuccessfullyDeletedNotificationMessage": "已删除 “{spaceName}” 空间。", "xpack.spaces.management.toggleAllFeaturesLink": "(全部更改)", - "xpack.spaces.management.unauthorizedPrompt.permissionDeniedDescription": "您没有权限管理空间。", "xpack.spaces.management.unauthorizedPrompt.permissionDeniedTitle": "权限被拒绝", "xpack.spaces.management.validateSpace.describeMaxLengthErrorMessage": "描述不能超过 2000 个字符。", "xpack.spaces.management.validateSpace.nameMaxLengthErrorMessage": "名称不能超过 1024 个字符。", @@ -18264,7 +18242,6 @@ "xpack.triggersActionsUI.sections.alertDetails.collapsedItemActons.muteTitle": "静音", "xpack.triggersActionsUI.sections.alertDetails.editAlertButtonLabel": "编辑", "xpack.triggersActionsUI.sections.alertDetails.unableToLoadAlertMessage": "无法加载告警:{message}", - "xpack.triggersActionsUI.sections.alertDetails.unableToLoadAlertStateMessage": "无法加载告警状态:{message}", "xpack.triggersActionsUI.sections.alertDetails.viewAlertInAppButtonLabel": "在应用中查看", "xpack.triggersActionsUI.sections.alertEdit.betaBadgeTooltipContent": "{pluginName} 为公测版,可能会进行更改。设计和代码相对于正式发行版功能还不够成熟,将按原样提供,且不提供任何保证。公测版功能不受正式发行版功能支持 SLA 的约束。", "xpack.triggersActionsUI.sections.alertEdit.cancelButtonLabel": "取消", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/case_mappings/field_mapping.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/field_mapping.tsx similarity index 95% rename from x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/case_mappings/field_mapping.tsx rename to x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/field_mapping.tsx index 52b881a1eb75..a3382513d2bc 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/case_mappings/field_mapping.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/field_mapping.tsx @@ -13,9 +13,8 @@ import * as i18n from './translations'; import { setActionTypeToMapping, setThirdPartyToMapping } from './utils'; import { ThirdPartyField as ConnectorConfigurationThirdPartyField } from './types'; -import { CasesConfigurationMapping } from '../types'; -import { connectorConfiguration } from '../config'; -import { createDefaultMapping } from '../servicenow_connectors'; +import { CasesConfigurationMapping } from './types'; +import { createDefaultMapping } from './utils'; const FieldRowWrapper = styled.div` margin-top: 8px; @@ -70,15 +69,15 @@ const getThirdPartyOptions = ( export interface FieldMappingProps { disabled: boolean; mapping: CasesConfigurationMapping[] | null; - connectorActionTypeId: string; onChangeMapping: (newMapping: CasesConfigurationMapping[]) => void; + connectorConfiguration: Record; } const FieldMappingComponent: React.FC = ({ disabled, mapping, onChangeMapping, - connectorActionTypeId, + connectorConfiguration, }) => { const onChangeActionType = useCallback( (caseField: string, newActionType: string) => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/case_mappings/field_mapping_row.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/field_mapping_row.tsx similarity index 100% rename from x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/case_mappings/field_mapping_row.tsx rename to x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/field_mapping_row.tsx diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/index.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/index.ts new file mode 100644 index 000000000000..2de9b87ead3f --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export * from './types'; +export * from './field_mapping'; +export * from './field_mapping_row'; +export * from './utils'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/case_mappings/translations.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/translations.ts similarity index 100% rename from x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/case_mappings/translations.ts rename to x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/translations.ts diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/case_mappings/types.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/types.ts similarity index 72% rename from x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/case_mappings/types.ts rename to x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/types.ts index 6cd2200e1dc7..3571db39b596 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/case_mappings/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/types.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ActionType } from '../../../../../types'; +import { ActionType } from '../../../../types'; export { ActionType }; @@ -14,3 +14,8 @@ export interface ThirdPartyField { defaultSourceField: string; defaultActionType: string; } +export interface CasesConfigurationMapping { + source: string; + target: string; + actionType: string; +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/case_mappings/utils.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/utils.ts similarity index 76% rename from x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/case_mappings/utils.ts rename to x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/utils.ts index a173d9051530..b14b1b76427c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/case_mappings/utils.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/case_mappings/utils.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { CasesConfigurationMapping } from '../types'; +import { CasesConfigurationMapping } from './types'; export const setActionTypeToMapping = ( caseField: string, @@ -36,3 +36,13 @@ export const setThirdPartyToMapping = ( } return item; }); + +export const createDefaultMapping = (fields: Record): CasesConfigurationMapping[] => + Object.keys(fields).map( + (key) => + ({ + source: fields[key].defaultSourceField, + target: key, + actionType: fields[key].defaultActionType, + } as CasesConfigurationMapping) + ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_params.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_params.test.tsx index ecdfefa109f5..be3e8a31820c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_params.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/email/email_params.test.tsx @@ -17,6 +17,7 @@ describe('EmailParamsFields renders', () => { subject: 'test', message: 'test message', }; + const wrapper = mountWithIntl( > { + return await http.post(`${BASE_ACTION_API_PATH}/action/${connectorId}/_execute`, { + body: JSON.stringify({ + params: { subAction: 'issueTypes', subActionParams: {} }, + }), + signal, + }); +} + +export async function getFieldsByIssueType({ + http, + signal, + connectorId, + id, +}: { + http: HttpSetup; + signal: AbortSignal; + connectorId: string; + id: string; +}): Promise> { + return await http.post(`${BASE_ACTION_API_PATH}/action/${connectorId}/_execute`, { + body: JSON.stringify({ + params: { subAction: 'fieldsByIssueType', subActionParams: { id } }, + }), + signal, + }); +} diff --git a/x-pack/plugins/security_solution/public/common/lib/connectors/jira/config.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/config.ts similarity index 87% rename from x-pack/plugins/security_solution/public/common/lib/connectors/jira/config.ts rename to x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/config.ts index e6151a54bff7..628600ee91c8 100644 --- a/x-pack/plugins/security_solution/public/common/lib/connectors/jira/config.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/config.ts @@ -4,19 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ConnectorConfiguration } from './types'; - import * as i18n from './translations'; import logo from './logo.svg'; -export const connector: ConnectorConfiguration = { +export const connectorConfiguration = { id: '.jira', name: i18n.JIRA_TITLE, logo, enabled: true, enabledInConfig: true, enabledInLicense: true, - minimumLicenseRequired: 'platinum', + minimumLicenseRequired: 'gold', fields: { summary: { label: i18n.MAPPING_FIELD_SUMMARY, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/index.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/index.ts new file mode 100644 index 000000000000..a0170f9d84e9 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { getActionType as getJiraActionType } from './jira'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira.test.tsx new file mode 100644 index 000000000000..61923d8f78b5 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira.test.tsx @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { TypeRegistry } from '../../../type_registry'; +import { registerBuiltInActionTypes } from '.././index'; +import { ActionTypeModel } from '../../../../types'; +import { JiraActionConnector } from './types'; + +const ACTION_TYPE_ID = '.jira'; +let actionTypeModel: ActionTypeModel; + +beforeAll(() => { + const actionTypeRegistry = new TypeRegistry(); + registerBuiltInActionTypes({ actionTypeRegistry }); + const getResult = actionTypeRegistry.get(ACTION_TYPE_ID); + if (getResult !== null) { + actionTypeModel = getResult; + } +}); + +describe('actionTypeRegistry.get() works', () => { + test('action type static data is as expected', () => { + expect(actionTypeModel.id).toEqual(ACTION_TYPE_ID); + }); +}); + +describe('jira connector validation', () => { + test('connector validation succeeds when connector config is valid', () => { + const actionConnector = { + secrets: { + email: 'email', + apiToken: 'apiToken', + }, + id: 'test', + actionTypeId: '.jira', + name: 'jira', + isPreconfigured: false, + config: { + apiUrl: 'https://siem-kibana.atlassian.net', + projectKey: 'CK', + }, + } as JiraActionConnector; + + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: { + apiUrl: [], + email: [], + apiToken: [], + projectKey: [], + }, + }); + }); + + test('connector validation fails when connector config is not valid', () => { + const actionConnector = ({ + secrets: { + email: 'user', + }, + id: '.jira', + actionTypeId: '.jira', + name: 'jira', + config: {}, + } as unknown) as JiraActionConnector; + + expect(actionTypeModel.validateConnector(actionConnector)).toEqual({ + errors: { + apiUrl: ['URL is required.'], + email: [], + apiToken: ['API token or Password is required'], + projectKey: ['Project key is required'], + }, + }); + }); +}); + +describe('jira action params validation', () => { + test('action params validation succeeds when action params is valid', () => { + const actionParams = { + subActionParams: { title: 'some title {{test}}' }, + }; + + expect(actionTypeModel.validateParams(actionParams)).toEqual({ + errors: { title: [] }, + }); + }); + + test('params validation fails when body is not valid', () => { + const actionParams = { + subActionParams: { title: '' }, + }; + + expect(actionTypeModel.validateParams(actionParams)).toEqual({ + errors: { + title: ['Title is required.'], + }, + }); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira.tsx new file mode 100644 index 000000000000..fd36bd6aeab0 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira.tsx @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { lazy } from 'react'; +import { ValidationResult, ActionTypeModel } from '../../../../types'; +import { connectorConfiguration } from './config'; +import logo from './logo.svg'; +import { JiraActionConnector, JiraActionParams } from './types'; +import * as i18n from './translations'; +import { isValidUrl } from '../../../lib/value_validators'; + +const validateConnector = (action: JiraActionConnector): ValidationResult => { + const validationResult = { errors: {} }; + const errors = { + apiUrl: new Array(), + projectKey: new Array(), + email: new Array(), + apiToken: new Array(), + }; + validationResult.errors = errors; + + if (!action.config.apiUrl) { + errors.apiUrl = [...errors.apiUrl, i18n.API_URL_REQUIRED]; + } + + if (action.config.apiUrl && !isValidUrl(action.config.apiUrl, 'https:')) { + errors.apiUrl = [...errors.apiUrl, i18n.API_URL_INVALID]; + } + + if (!action.config.projectKey) { + errors.projectKey = [...errors.projectKey, i18n.JIRA_PROJECT_KEY_REQUIRED]; + } + + if (!action.secrets.email) { + errors.email = [...errors.email, i18n.JIRA_EMAIL_REQUIRED]; + } + + if (!action.secrets.apiToken) { + errors.apiToken = [...errors.apiToken, i18n.JIRA_API_TOKEN_REQUIRED]; + } + + return validationResult; +}; + +export function getActionType(): ActionTypeModel { + return { + id: connectorConfiguration.id, + iconClass: logo, + selectMessage: i18n.JIRA_DESC, + actionTypeTitle: connectorConfiguration.name, + validateConnector, + actionConnectorFields: lazy(() => import('./jira_connectors')), + validateParams: (actionParams: JiraActionParams): ValidationResult => { + const validationResult = { errors: {} }; + const errors = { + title: new Array(), + }; + validationResult.errors = errors; + if (actionParams.subActionParams && !actionParams.subActionParams.title?.length) { + errors.title.push(i18n.TITLE_REQUIRED); + } + return validationResult; + }, + actionParamsFields: lazy(() => import('./jira_params')), + }; +} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_connectors.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_connectors.test.tsx new file mode 100644 index 000000000000..2cac1819d552 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_connectors.test.tsx @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React from 'react'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { DocLinksStart } from 'kibana/public'; +import JiraConnectorFields from './jira_connectors'; +import { JiraActionConnector } from './types'; + +describe('JiraActionConnectorFields renders', () => { + test('alerting Jira connector fields is rendered', () => { + const actionConnector = { + secrets: { + email: 'email', + apiToken: 'token', + }, + id: 'test', + actionTypeId: '.jira', + isPreconfigured: false, + name: 'jira', + config: { + apiUrl: 'https://test/', + projectKey: 'CK', + }, + } as JiraActionConnector; + const deps = { + docLinks: { ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart, + }; + const wrapper = mountWithIntl( + {}} + editActionSecrets={() => {}} + docLinks={deps!.docLinks} + readOnly={false} + /> + ); + + expect(wrapper.find('[data-test-subj="apiUrlFromInput"]').length > 0).toBeTruthy(); + expect( + wrapper.find('[data-test-subj="connector-jira-project-key-form-input"]').length > 0 + ).toBeTruthy(); + + expect( + wrapper.find('[data-test-subj="connector-jira-email-form-input"]').length > 0 + ).toBeTruthy(); + + expect( + wrapper.find('[data-test-subj="connector-jira-apiToken-form-input"]').length > 0 + ).toBeTruthy(); + }); + + test('case specific Jira connector fields is rendered', () => { + const actionConnector = { + secrets: { + email: 'email', + apiToken: 'token', + }, + id: 'test', + actionTypeId: '.jira', + isPreconfigured: false, + name: 'jira', + config: { + apiUrl: 'https://test/', + projectKey: 'CK', + }, + } as JiraActionConnector; + const deps = { + docLinks: { ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart, + }; + const wrapper = mountWithIntl( + {}} + editActionSecrets={() => {}} + docLinks={deps!.docLinks} + readOnly={false} + consumer={'case'} + /> + ); + expect(wrapper.find('[data-test-subj="case-jira-mappings"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="apiUrlFromInput"]').length > 0).toBeTruthy(); + expect( + wrapper.find('[data-test-subj="connector-jira-project-key-form-input"]').length > 0 + ).toBeTruthy(); + + expect( + wrapper.find('[data-test-subj="connector-jira-email-form-input"]').length > 0 + ).toBeTruthy(); + + expect( + wrapper.find('[data-test-subj="connector-jira-apiToken-form-input"]').length > 0 + ).toBeTruthy(); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_connectors.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_connectors.tsx new file mode 100644 index 000000000000..2ab9843c143b --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_connectors.tsx @@ -0,0 +1,209 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React, { useCallback } from 'react'; + +import { + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiFieldPassword, + EuiSpacer, +} from '@elastic/eui'; + +import { isEmpty } from 'lodash'; +import { ActionConnectorFieldsProps } from '../../../../types'; +import { CasesConfigurationMapping, FieldMapping, createDefaultMapping } from '../case_mappings'; + +import * as i18n from './translations'; +import { JiraActionConnector } from './types'; +import { connectorConfiguration } from './config'; + +const JiraConnectorFields: React.FC> = ({ + action, + editActionSecrets, + editActionConfig, + errors, + consumer, + readOnly, + docLinks, +}) => { + // TODO: remove incidentConfiguration later, when Case Jira will move their fields to the level of action execution + const { apiUrl, projectKey, incidentConfiguration, isCaseOwned } = action.config; + const mapping = incidentConfiguration ? incidentConfiguration.mapping : []; + + const isApiUrlInvalid: boolean = errors.apiUrl.length > 0 && apiUrl != null; + + const { email, apiToken } = action.secrets; + + const isProjectKeyInvalid: boolean = errors.projectKey.length > 0 && projectKey != null; + const isEmailInvalid: boolean = errors.email.length > 0 && email != null; + const isApiTokenInvalid: boolean = errors.apiToken.length > 0 && apiToken != null; + + // TODO: remove this block later, when Case ServiceNow will move their fields to the level of action execution + if (consumer === 'case') { + if (isEmpty(mapping)) { + editActionConfig('incidentConfiguration', { + mapping: createDefaultMapping(connectorConfiguration.fields as any), + }); + } + if (!isCaseOwned) { + editActionConfig('isCaseOwned', true); + } + } + + const handleOnChangeActionConfig = useCallback( + (key: string, value: string) => editActionConfig(key, value), + // eslint-disable-next-line react-hooks/exhaustive-deps + [] + ); + + const handleOnChangeSecretConfig = useCallback( + (key: string, value: string) => editActionSecrets(key, value), + // eslint-disable-next-line react-hooks/exhaustive-deps + [] + ); + + const handleOnChangeMappingConfig = useCallback( + (newMapping: CasesConfigurationMapping[]) => + editActionConfig('incidentConfiguration', { + ...action.config.incidentConfiguration, + mapping: newMapping, + }), + // eslint-disable-next-line react-hooks/exhaustive-deps + [action.config] + ); + + return ( + <> + + + + handleOnChangeActionConfig('apiUrl', evt.target.value)} + onBlur={() => { + if (!apiUrl) { + editActionConfig('apiUrl', ''); + } + }} + /> + + + + + + + + handleOnChangeActionConfig('projectKey', evt.target.value)} + onBlur={() => { + if (!projectKey) { + editActionConfig('projectKey', ''); + } + }} + /> + + + + + + + + handleOnChangeSecretConfig('email', evt.target.value)} + onBlur={() => { + if (!email) { + editActionSecrets('email', ''); + } + }} + /> + + + + + + + + handleOnChangeSecretConfig('apiToken', evt.target.value)} + onBlur={() => { + if (!apiToken) { + editActionSecrets('apiToken', ''); + } + }} + /> + + + + {consumer === 'case' && ( // TODO: remove this block later, when Case Jira will move their fields to the level of action execution + <> + + + + + + + + )} + + ); +}; + +// eslint-disable-next-line import/no-default-export +export { JiraConnectorFields as default }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.test.tsx new file mode 100644 index 000000000000..26d358310741 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.test.tsx @@ -0,0 +1,233 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React from 'react'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import JiraParamsFields from './jira_params'; +import { DocLinksStart } from 'kibana/public'; + +import { useGetIssueTypes } from './use_get_issue_types'; +import { useGetFieldsByIssueType } from './use_get_fields_by_issue_type'; + +jest.mock('../../../app_context', () => { + const post = jest.fn(); + return { + useAppDependencies: jest.fn(() => ({ http: { post } })), + }; +}); + +jest.mock('./use_get_issue_types'); +jest.mock('./use_get_fields_by_issue_type'); + +const useGetIssueTypesMock = useGetIssueTypes as jest.Mock; +const useGetFieldsByIssueTypeMock = useGetFieldsByIssueType as jest.Mock; + +const actionParams = { + subAction: 'pushToService', + subActionParams: { + title: 'sn title', + description: 'some description', + comments: [{ commentId: '1', comment: 'comment for jira' }], + issueType: '10006', + labels: ['kibana'], + priority: 'High', + savedObjectId: '123', + externalId: null, + }, +}; +const connector = { + secrets: {}, + config: {}, + id: 'test', + actionTypeId: '.test', + name: 'Test', + isPreconfigured: false, +}; + +describe('JiraParamsFields renders', () => { + const useGetIssueTypesResponse = { + isLoading: false, + issueTypes: [ + { + id: '10006', + name: 'Task', + }, + { + id: '10007', + name: 'Bug', + }, + ], + }; + + const useGetFieldsByIssueTypeResponse = { + isLoading: false, + fields: { + summary: { allowedValues: [], defaultValue: {} }, + labels: { allowedValues: [], defaultValue: {} }, + description: { allowedValues: [], defaultValue: {} }, + priority: { + allowedValues: [ + { + name: 'Medium', + id: '3', + }, + ], + defaultValue: { name: 'Medium', id: '3' }, + }, + }, + }; + + beforeEach(() => { + useGetIssueTypesMock.mockReturnValue(useGetIssueTypesResponse); + useGetFieldsByIssueTypeMock.mockReturnValue(useGetFieldsByIssueTypeResponse); + }); + + test('all params fields are rendered', () => { + const wrapper = mountWithIntl( + {}} + index={0} + messageVariables={[]} + docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + actionConnector={connector} + /> + ); + expect(wrapper.find('[data-test-subj="issueTypeSelect"]').first().prop('value')).toStrictEqual( + '10006' + ); + expect(wrapper.find('[data-test-subj="prioritySelect"]').first().prop('value')).toStrictEqual( + 'High' + ); + expect(wrapper.find('[data-test-subj="titleInput"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="descriptionTextArea"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="labelsComboBox"]').length > 0).toBeTruthy(); + expect(wrapper.find('[data-test-subj="commentsTextArea"]').length > 0).toBeTruthy(); + }); + + test('it shows loading when loading issue types', () => { + useGetIssueTypesMock.mockReturnValue({ ...useGetIssueTypesResponse, isLoading: true }); + const wrapper = mountWithIntl( + {}} + index={0} + messageVariables={[]} + docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + actionConnector={connector} + /> + ); + + expect( + wrapper.find('[data-test-subj="issueTypeSelect"]').first().prop('isLoading') + ).toBeTruthy(); + }); + + test('it shows loading when loading fields', () => { + useGetFieldsByIssueTypeMock.mockReturnValue({ + ...useGetFieldsByIssueTypeResponse, + isLoading: true, + }); + + const wrapper = mountWithIntl( + {}} + index={0} + messageVariables={[]} + docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + actionConnector={connector} + /> + ); + + expect( + wrapper.find('[data-test-subj="prioritySelect"]').first().prop('isLoading') + ).toBeTruthy(); + expect( + wrapper.find('[data-test-subj="labelsComboBox"]').first().prop('isLoading') + ).toBeTruthy(); + }); + + test('it disabled the fields when loading issue types', () => { + useGetIssueTypesMock.mockReturnValue({ ...useGetIssueTypesResponse, isLoading: true }); + + const wrapper = mountWithIntl( + {}} + index={0} + messageVariables={[]} + docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + actionConnector={connector} + /> + ); + + expect( + wrapper.find('[data-test-subj="issueTypeSelect"]').first().prop('disabled') + ).toBeTruthy(); + expect(wrapper.find('[data-test-subj="prioritySelect"]').first().prop('disabled')).toBeTruthy(); + expect( + wrapper.find('[data-test-subj="labelsComboBox"]').first().prop('isDisabled') + ).toBeTruthy(); + }); + + test('it disabled the fields when loading fields', () => { + useGetFieldsByIssueTypeMock.mockReturnValue({ + ...useGetFieldsByIssueTypeResponse, + isLoading: true, + }); + + const wrapper = mountWithIntl( + {}} + index={0} + messageVariables={[]} + docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + actionConnector={connector} + /> + ); + + expect( + wrapper.find('[data-test-subj="issueTypeSelect"]').first().prop('disabled') + ).toBeTruthy(); + expect(wrapper.find('[data-test-subj="prioritySelect"]').first().prop('disabled')).toBeTruthy(); + expect( + wrapper.find('[data-test-subj="labelsComboBox"]').first().prop('isDisabled') + ).toBeTruthy(); + }); + + test('hide unsupported fields', () => { + useGetIssueTypesMock.mockReturnValue(useGetIssueTypesResponse); + useGetFieldsByIssueTypeMock.mockReturnValue({ + ...useGetFieldsByIssueTypeResponse, + fields: {}, + }); + const wrapper = mountWithIntl( + {}} + index={0} + messageVariables={[]} + docLinks={{ ELASTIC_WEBSITE_URL: '', DOC_LINK_VERSION: '' } as DocLinksStart} + actionConnector={connector} + /> + ); + + expect(wrapper.find('[data-test-subj="issueTypeSelect"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="titleInput"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="commentsTextArea"]').exists()).toBeTruthy(); + + expect(wrapper.find('[data-test-subj="prioritySelect"]').exists()).toBeFalsy(); + expect(wrapper.find('[data-test-subj="descriptionTextArea"]').exists()).toBeFalsy(); + expect(wrapper.find('[data-test-subj="labelsComboBox"]').exists()).toBeFalsy(); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.tsx new file mode 100644 index 000000000000..bde3d67ffd65 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/jira_params.tsx @@ -0,0 +1,319 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { Fragment, useEffect, useState, useMemo } from 'react'; +import { map } from 'lodash/fp'; +import { EuiFormRow, EuiComboBox, EuiSelectOption, EuiHorizontalRule } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { EuiSelect } from '@elastic/eui'; +import { EuiFlexGroup } from '@elastic/eui'; +import { EuiFlexItem } from '@elastic/eui'; +import { EuiSpacer } from '@elastic/eui'; + +import { useAppDependencies } from '../../../app_context'; +import { ActionParamsProps } from '../../../../types'; +import { TextAreaWithMessageVariables } from '../../text_area_with_message_variables'; +import { TextFieldWithMessageVariables } from '../../text_field_with_message_variables'; +import { JiraActionParams } from './types'; +import { useGetIssueTypes } from './use_get_issue_types'; +import { useGetFieldsByIssueType } from './use_get_fields_by_issue_type'; + +const JiraParamsFields: React.FunctionComponent> = ({ + actionParams, + editAction, + index, + errors, + messageVariables, + actionConnector, +}) => { + const { title, description, comments, issueType, priority, labels, savedObjectId } = + actionParams.subActionParams || {}; + + const [issueTypesSelectOptions, setIssueTypesSelectOptions] = useState([]); + const [firstLoad, setFirstLoad] = useState(false); + const [prioritiesSelectOptions, setPrioritiesSelectOptions] = useState([]); + const { http, toastNotifications } = useAppDependencies(); + + useEffect(() => { + setFirstLoad(true); + }, []); + + const { isLoading: isLoadingIssueTypes, issueTypes } = useGetIssueTypes({ + http, + toastNotifications, + actionConnector, + }); + + const { isLoading: isLoadingFields, fields } = useGetFieldsByIssueType({ + http, + toastNotifications, + actionConnector, + issueType, + }); + + const hasLabels = useMemo(() => Object.prototype.hasOwnProperty.call(fields, 'labels'), [fields]); + const hasDescription = useMemo( + () => Object.prototype.hasOwnProperty.call(fields, 'description'), + [fields] + ); + const hasPriority = useMemo(() => Object.prototype.hasOwnProperty.call(fields, 'priority'), [ + fields, + ]); + + useEffect(() => { + const options = issueTypes.map((type) => ({ + value: type.id ?? '', + text: type.name ?? '', + })); + + setIssueTypesSelectOptions(options); + }, [issueTypes]); + + useEffect(() => { + if (issueType != null && fields != null) { + const priorities = fields.priority?.allowedValues ?? []; + const options = map( + (p) => ({ + value: p.name, + text: p.name, + }), + priorities + ); + setPrioritiesSelectOptions(options); + } + }, [fields, issueType]); + + const labelOptions = useMemo(() => (labels ? labels.map((label: string) => ({ label })) : []), [ + labels, + ]); + + const editSubActionProperty = (key: string, value: any) => { + const newProps = { ...actionParams.subActionParams, [key]: value }; + editAction('subActionParams', newProps, index); + }; + + // Reset parameters when changing connector + useEffect(() => { + if (!firstLoad) { + return; + } + + setIssueTypesSelectOptions([]); + editAction('subActionParams', { title, comments, description: '', savedObjectId }, index); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [actionConnector]); + + // Reset fields when changing connector or issue type + useEffect(() => { + if (!firstLoad) { + return; + } + + setPrioritiesSelectOptions([]); + editAction( + 'subActionParams', + { title, issueType, comments, description: '', savedObjectId }, + index + ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [issueType, savedObjectId]); + + useEffect(() => { + if (!actionParams.subAction) { + editAction('subAction', 'pushToService', index); + } + if (!savedObjectId && messageVariables?.find((variable) => variable.name === 'alertId')) { + editSubActionProperty('savedObjectId', '{{alertId}}'); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ + actionConnector, + actionParams.subAction, + index, + savedObjectId, + issueTypesSelectOptions, + issueType, + ]); + + // Set default issue type + useEffect(() => { + if (!issueType && issueTypesSelectOptions.length > 0) { + editSubActionProperty('issueType', issueTypesSelectOptions[0].value as string); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [issueTypes, issueTypesSelectOptions]); + + // Set default priority + useEffect(() => { + if (!priority && prioritiesSelectOptions.length > 0) { + editSubActionProperty('priority', prioritiesSelectOptions[0].value as string); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [actionConnector, issueType, prioritiesSelectOptions]); + + return ( + + <> + + { + editSubActionProperty('issueType', e.target.value); + }} + /> + + + <> + {hasPriority && ( + <> + + + + { + editSubActionProperty('priority', e.target.value); + }} + /> + + + + + + )} + 0 && title !== undefined} + label={i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.titleFieldLabel', + { + defaultMessage: 'Summary', + } + )} + > + + + + {hasLabels && ( + <> + + + + { + const newOptions = [...labelOptions, { label: searchValue }]; + editSubActionProperty( + 'labels', + newOptions.map((newOption) => newOption.label) + ); + }} + onChange={(selectedOptions: Array<{ label: string }>) => { + editSubActionProperty( + 'labels', + selectedOptions.map((selectedOption) => selectedOption.label) + ); + }} + onBlur={() => { + if (!labels) { + editSubActionProperty('labels', []); + } + }} + isClearable={true} + data-test-subj="labelsComboBox" + /> + + + + + + )} + {hasDescription && ( + + )} + { + editSubActionProperty(key, [{ commentId: '1', comment: value }]); + }} + messageVariables={messageVariables} + paramsProperty={'comments'} + inputTargetValue={comments && comments.length > 0 ? comments[0].comment : ''} + label={i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.commentsTextAreaFieldLabel', + { + defaultMessage: 'Additional comments (optional)', + } + )} + errors={errors.comments as string[]} + /> + + + + ); +}; + +// eslint-disable-next-line import/no-default-export +export { JiraParamsFields as default }; diff --git a/x-pack/plugins/security_solution/public/common/lib/connectors/jira/logo.svg b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/logo.svg similarity index 100% rename from x-pack/plugins/security_solution/public/common/lib/connectors/jira/logo.svg rename to x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/logo.svg diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/translations.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/translations.ts new file mode 100644 index 000000000000..bfcb72d1cb97 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/translations.ts @@ -0,0 +1,133 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +export const JIRA_DESC = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.selectMessageText', + { + defaultMessage: 'Push or update data to a new issue in Jira', + } +); + +export const JIRA_TITLE = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.actionTypeTitle', + { + defaultMessage: 'Jira', + } +); + +export const API_URL_LABEL = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.apiUrlTextFieldLabel', + { + defaultMessage: 'URL', + } +); + +export const API_URL_REQUIRED = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.requiredApiUrlTextField', + { + defaultMessage: 'URL is required.', + } +); + +export const API_URL_INVALID = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.invalidApiUrlTextField', + { + defaultMessage: 'URL is invalid.', + } +); + +export const JIRA_PROJECT_KEY_LABEL = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.projectKey', + { + defaultMessage: 'Project key', + } +); + +export const JIRA_PROJECT_KEY_REQUIRED = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.requiredProjectKeyTextField', + { + defaultMessage: 'Project key is required', + } +); + +export const JIRA_EMAIL_LABEL = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.emailTextFieldLabel', + { + defaultMessage: 'Email or Username', + } +); + +export const JIRA_EMAIL_REQUIRED = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.requiredEmailTextField', + { + defaultMessage: 'Email or Username is required', + } +); + +export const JIRA_API_TOKEN_LABEL = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.apiTokenTextFieldLabel', + { + defaultMessage: 'API token or Password', + } +); + +export const JIRA_API_TOKEN_REQUIRED = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.requiredApiTokenTextField', + { + defaultMessage: 'API token or Password is required', + } +); + +export const MAPPING_FIELD_SUMMARY = i18n.translate( + 'xpack.triggersActionsUI.case.configureCases.mappingFieldSummary', + { + defaultMessage: 'Summary', + } +); + +export const DESCRIPTION_REQUIRED = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.requiredDescriptionTextField', + { + defaultMessage: 'Description is required.', + } +); + +export const TITLE_REQUIRED = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.requiredTitleTextField', + { + defaultMessage: 'Title is required.', + } +); + +export const MAPPING_FIELD_DESC = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.mappingFieldDescription', + { + defaultMessage: 'Description', + } +); + +export const MAPPING_FIELD_COMMENTS = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.mappingFieldComments', + { + defaultMessage: 'Comments', + } +); + +export const ISSUE_TYPES_API_ERROR = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.unableToGetIssueTypesMessage', + { + defaultMessage: 'Unable to get issue types', + } +); + +export const FIELDS_API_ERROR = i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.jira.unableToGetFieldsMessage', + { + defaultMessage: 'Unable to get fields', + } +); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/types.ts b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/types.ts new file mode 100644 index 000000000000..ff11199f35fe --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/types.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { CasesConfigurationMapping } from '../case_mappings'; + +export interface JiraActionConnector { + config: JiraConfig; + secrets: JiraSecrets; +} + +export interface JiraActionParams { + subAction: string; + subActionParams: { + savedObjectId: string; + title: string; + description: string; + comments: Array<{ commentId: string; comment: string }>; + externalId: string | null; + issueType: string; + priority: string; + labels: string[]; + }; +} + +interface IncidentConfiguration { + mapping: CasesConfigurationMapping[]; +} + +interface JiraConfig { + apiUrl: string; + projectKey: string; + incidentConfiguration?: IncidentConfiguration; + isCaseOwned?: boolean; +} + +interface JiraSecrets { + email: string; + apiToken: string; +} + +// to remove diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_fields_by_issue_type.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_fields_by_issue_type.tsx new file mode 100644 index 000000000000..08715822e527 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_fields_by_issue_type.tsx @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useState, useEffect, useRef } from 'react'; +import { HttpSetup, ToastsApi } from 'kibana/public'; +import { ActionConnector } from '../../../../types'; +import { getFieldsByIssueType } from './api'; +import * as i18n from './translations'; + +interface Fields { + [key: string]: { + allowedValues: Array<{ name: string; id: string }> | []; + defaultValue: { name: string; id: string } | {}; + }; +} + +interface Props { + http: HttpSetup; + toastNotifications: Pick< + ToastsApi, + 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' + >; + issueType: string; + actionConnector?: ActionConnector; +} + +export interface UseGetFieldsByIssueType { + fields: Fields; + isLoading: boolean; +} + +export const useGetFieldsByIssueType = ({ + http, + toastNotifications, + actionConnector, + issueType, +}: Props): UseGetFieldsByIssueType => { + const [isLoading, setIsLoading] = useState(true); + const [fields, setFields] = useState({}); + const abortCtrl = useRef(new AbortController()); + + useEffect(() => { + let didCancel = false; + const fetchData = async () => { + if (!actionConnector || !issueType) { + setIsLoading(false); + return; + } + + abortCtrl.current = new AbortController(); + setIsLoading(true); + try { + const res = await getFieldsByIssueType({ + http, + signal: abortCtrl.current.signal, + connectorId: actionConnector.id, + id: issueType, + }); + + if (!didCancel) { + setIsLoading(false); + setFields(res.data ?? {}); + if (res.status && res.status === 'error') { + toastNotifications.addDanger({ + title: i18n.FIELDS_API_ERROR, + text: `${res.serviceMessage ?? res.message}`, + }); + } + } + } catch (error) { + if (!didCancel) { + toastNotifications.addDanger({ + title: i18n.FIELDS_API_ERROR, + text: error.message, + }); + } + } + }; + + abortCtrl.current.abort(); + fetchData(); + + return () => { + didCancel = true; + setIsLoading(false); + abortCtrl.current.abort(); + }; + }, [http, actionConnector, issueType, toastNotifications]); + + return { + isLoading, + fields, + }; +}; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_issue_types.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_issue_types.tsx new file mode 100644 index 000000000000..9ebaf5882d9b --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/jira/use_get_issue_types.tsx @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useState, useEffect, useRef } from 'react'; +import { HttpSetup, ToastsApi } from 'kibana/public'; +import { ActionConnector } from '../../../../types'; +import { getIssueTypes } from './api'; +import * as i18n from './translations'; + +type IssueTypes = Array<{ id: string; name: string }>; + +interface Props { + http: HttpSetup; + toastNotifications: Pick< + ToastsApi, + 'get$' | 'add' | 'remove' | 'addSuccess' | 'addWarning' | 'addDanger' | 'addError' + >; + actionConnector?: ActionConnector; +} + +export interface UseGetIssueTypes { + issueTypes: IssueTypes; + isLoading: boolean; +} + +export const useGetIssueTypes = ({ + http, + actionConnector, + toastNotifications, +}: Props): UseGetIssueTypes => { + const [isLoading, setIsLoading] = useState(true); + const [issueTypes, setIssueTypes] = useState([]); + const abortCtrl = useRef(new AbortController()); + + useEffect(() => { + let didCancel = false; + const fetchData = async () => { + if (!actionConnector) { + setIsLoading(false); + return; + } + + abortCtrl.current = new AbortController(); + setIsLoading(true); + + try { + const res = await getIssueTypes({ + http, + signal: abortCtrl.current.signal, + connectorId: actionConnector.id, + }); + + if (!didCancel) { + setIsLoading(false); + setIssueTypes(res.data ?? []); + if (res.status && res.status === 'error') { + toastNotifications.addDanger({ + title: i18n.ISSUE_TYPES_API_ERROR, + text: `${res.serviceMessage ?? res.message}`, + }); + } + } + } catch (error) { + if (!didCancel) { + toastNotifications.addDanger({ + title: i18n.ISSUE_TYPES_API_ERROR, + text: error.message, + }); + } + } + }; + + abortCtrl.current.abort(); + fetchData(); + + return () => { + didCancel = true; + setIsLoading(false); + abortCtrl.current.abort(); + }; + }, [http, actionConnector, toastNotifications]); + + return { + issueTypes, + isLoading, + }; +}; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_connectors.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_connectors.tsx index f99a276305d7..a8f1ed8d5544 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_connectors.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_connectors.tsx @@ -18,10 +18,11 @@ import { import { isEmpty } from 'lodash'; import { FormattedMessage } from '@kbn/i18n/react'; import { ActionConnectorFieldsProps } from '../../../../types'; +import { CasesConfigurationMapping, FieldMapping, createDefaultMapping } from '../case_mappings'; + import * as i18n from './translations'; -import { ServiceNowActionConnector, CasesConfigurationMapping } from './types'; +import { ServiceNowActionConnector } from './types'; import { connectorConfiguration } from './config'; -import { FieldMapping } from './case_mappings/field_mapping'; const ServiceNowConnectorFields: React.FC @@ -184,15 +185,5 @@ const ServiceNowConnectorFields: React.FC): CasesConfigurationMapping[] => - Object.keys(fields).map( - (key) => - ({ - source: fields[key].defaultSourceField, - target: key, - actionType: fields[key].defaultActionType, - } as CasesConfigurationMapping) - ); - // eslint-disable-next-line import/no-default-export export { ServiceNowConnectorFields as default }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_params.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_params.tsx index 2a29018d83ff..2a2efdfbe35b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_params.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/servicenow/servicenow_params.tsx @@ -79,7 +79,14 @@ const ServiceNowParamsFields: React.FunctionComponent -

Incident

+

+ {i18n.translate( + 'xpack.triggersActionsUI.components.builtinActionTypes.serviceNow.title', + { + defaultMessage: 'Incident', + } + )} +

{ return await http.get(`${BASE_ALERT_API_PATH}/list_alert_types`); @@ -48,14 +54,14 @@ export async function loadAlertState({ }); } -export async function loadAlertStatus({ +export async function loadAlertInstanceSummary({ http, alertId, }: { http: HttpSetup; alertId: string; -}): Promise { - return await http.get(`${BASE_ALERT_API_PATH}/alert/${alertId}/status`); +}): Promise { + return await http.get(`${BASE_ALERT_API_PATH}/alert/${alertId}/_instance_summary`); } export async function loadAlerts({ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx index 2d4507ca9307..ac5b2a2187c2 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx @@ -311,6 +311,7 @@ export const ActionForm = ({ messageVariables={messageVariables} defaultMessage={defaultActionMessage ?? undefined} docLinks={docLinks} + actionConnector={actionConnector} /> ) : null} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.test.tsx index ff9b518a9f5b..f59b836a7936 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.test.tsx @@ -7,7 +7,7 @@ import * as React from 'react'; import uuid from 'uuid'; import { shallow } from 'enzyme'; import { AlertInstances, AlertInstanceListItem, alertInstanceToListItem } from './alert_instances'; -import { Alert, AlertStatus, AlertInstanceStatus } from '../../../../types'; +import { Alert, AlertInstanceSummary, AlertInstanceStatus } from '../../../../types'; import { EuiBasicTable } from '@elastic/eui'; const fakeNow = new Date('2020-02-09T23:15:41.941Z'); @@ -34,7 +34,7 @@ jest.mock('../../../app_context', () => { describe('alert_instances', () => { it('render a list of alert instances', () => { const alert = mockAlert(); - const alertStatus = mockAlertStatus({ + const alertInstanceSummary = mockAlertInstanceSummary({ instances: { first_instance: { status: 'OK', @@ -52,19 +52,24 @@ describe('alert_instances', () => { fakeNow.getTime(), alert, 'first_instance', - alertStatus.instances.first_instance + alertInstanceSummary.instances.first_instance ), alertInstanceToListItem( fakeNow.getTime(), alert, 'second_instance', - alertStatus.instances.second_instance + alertInstanceSummary.instances.second_instance ), ]; expect( shallow( - + ) .find(EuiBasicTable) .prop('items') @@ -73,7 +78,7 @@ describe('alert_instances', () => { it('render a hidden field with duration epoch', () => { const alert = mockAlert(); - const alertStatus = mockAlertStatus(); + const alertInstanceSummary = mockAlertInstanceSummary(); expect( shallow( @@ -82,7 +87,7 @@ describe('alert_instances', () => { {...mockAPIs} alert={alert} readOnly={false} - alertStatus={alertStatus} + alertInstanceSummary={alertInstanceSummary} /> ) .find('[name="alertInstancesDurationEpoch"]') @@ -108,7 +113,7 @@ describe('alert_instances', () => { {...mockAPIs} alert={alert} readOnly={false} - alertStatus={mockAlertStatus({ + alertInstanceSummary={mockAlertInstanceSummary({ instances, })} /> @@ -134,7 +139,7 @@ describe('alert_instances', () => { {...mockAPIs} alert={alert} readOnly={false} - alertStatus={mockAlertStatus({ + alertInstanceSummary={mockAlertInstanceSummary({ instances: { 'us-west': { status: 'OK', @@ -253,8 +258,10 @@ function mockAlert(overloads: Partial = {}): Alert { }; } -function mockAlertStatus(overloads: Partial = {}): AlertStatus { - const status: AlertStatus = { +function mockAlertInstanceSummary( + overloads: Partial = {} +): AlertInstanceSummary { + const summary: AlertInstanceSummary = { id: 'alert-id', name: 'alert-name', tags: ['tag-1', 'tag-2'], @@ -274,5 +281,5 @@ function mockAlertStatus(overloads: Partial = {}): AlertStatus { }, }, }; - return { ...status, ...overloads }; + return { ...summary, ...overloads }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.tsx index 77a3b454a182..44d65eafc241 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances.tsx @@ -11,7 +11,7 @@ import { EuiBasicTable, EuiHealth, EuiSpacer, EuiSwitch } from '@elastic/eui'; // @ts-ignore import { RIGHT_ALIGNMENT, CENTER_ALIGNMENT } from '@elastic/eui/lib/services'; import { padStart, chunk } from 'lodash'; -import { Alert, AlertStatus, AlertInstanceStatus, Pagination } from '../../../../types'; +import { Alert, AlertInstanceSummary, AlertInstanceStatus, Pagination } from '../../../../types'; import { ComponentOpts as AlertApis, withBulkAlertOperations, @@ -21,7 +21,7 @@ import { DEFAULT_SEARCH_PAGE_SIZE } from '../../../constants'; type AlertInstancesProps = { alert: Alert; readOnly: boolean; - alertStatus: AlertStatus; + alertInstanceSummary: AlertInstanceSummary; requestRefresh: () => Promise; durationEpoch?: number; } & Pick; @@ -113,7 +113,7 @@ function durationAsString(duration: Duration): string { export function AlertInstances({ alert, readOnly, - alertStatus, + alertInstanceSummary, muteAlertInstance, unmuteAlertInstance, requestRefresh, @@ -124,7 +124,9 @@ export function AlertInstances({ size: DEFAULT_SEARCH_PAGE_SIZE, }); - const alertInstances = Object.entries(alertStatus.instances).map(([instanceId, instance]) => + const alertInstances = Object.entries( + alertInstanceSummary.instances + ).map(([instanceId, instance]) => alertInstanceToListItem(durationEpoch, alert, instanceId, instance) ); const pageOfAlertInstances = getPage(alertInstances, pagination); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.test.tsx index 61af8f547852..d92148a8fea5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.test.tsx @@ -7,8 +7,8 @@ import * as React from 'react'; import uuid from 'uuid'; import { shallow } from 'enzyme'; import { ToastsApi } from 'kibana/public'; -import { AlertInstancesRoute, getAlertStatus } from './alert_instances_route'; -import { Alert, AlertStatus } from '../../../../types'; +import { AlertInstancesRoute, getAlertInstanceSummary } from './alert_instances_route'; +import { Alert, AlertInstanceSummary } from '../../../../types'; import { EuiLoadingSpinner } from '@elastic/eui'; const fakeNow = new Date('2020-02-09T23:15:41.941Z'); @@ -20,7 +20,7 @@ jest.mock('../../../app_context', () => { useAppDependencies: jest.fn(() => ({ toastNotifications })), }; }); -describe('alert_status_route', () => { +describe('alert_instance_summary_route', () => { it('render a loader while fetching data', () => { const alert = mockAlert(); @@ -37,25 +37,30 @@ describe('getAlertState useEffect handler', () => { jest.clearAllMocks(); }); - it('fetches alert status', async () => { + it('fetches alert instance summary', async () => { const alert = mockAlert(); - const alertStatus = mockAlertStatus(); - const { loadAlertStatus } = mockApis(); - const { setAlertStatus } = mockStateSetter(); + const alertInstanceSummary = mockAlertInstanceSummary(); + const { loadAlertInstanceSummary } = mockApis(); + const { setAlertInstanceSummary } = mockStateSetter(); - loadAlertStatus.mockImplementationOnce(async () => alertStatus); + loadAlertInstanceSummary.mockImplementationOnce(async () => alertInstanceSummary); const toastNotifications = ({ addDanger: jest.fn(), } as unknown) as ToastsApi; - await getAlertStatus(alert.id, loadAlertStatus, setAlertStatus, toastNotifications); + await getAlertInstanceSummary( + alert.id, + loadAlertInstanceSummary, + setAlertInstanceSummary, + toastNotifications + ); - expect(loadAlertStatus).toHaveBeenCalledWith(alert.id); - expect(setAlertStatus).toHaveBeenCalledWith(alertStatus); + expect(loadAlertInstanceSummary).toHaveBeenCalledWith(alert.id); + expect(setAlertInstanceSummary).toHaveBeenCalledWith(alertInstanceSummary); }); - it('displays an error if the alert status isnt found', async () => { + it('displays an error if the alert instance summary isnt found', async () => { const actionType = { id: '.server-log', name: 'Server log', @@ -72,34 +77,39 @@ describe('getAlertState useEffect handler', () => { ], }); - const { loadAlertStatus } = mockApis(); - const { setAlertStatus } = mockStateSetter(); + const { loadAlertInstanceSummary } = mockApis(); + const { setAlertInstanceSummary } = mockStateSetter(); - loadAlertStatus.mockImplementation(async () => { + loadAlertInstanceSummary.mockImplementation(async () => { throw new Error('OMG'); }); const toastNotifications = ({ addDanger: jest.fn(), } as unknown) as ToastsApi; - await getAlertStatus(alert.id, loadAlertStatus, setAlertStatus, toastNotifications); + await getAlertInstanceSummary( + alert.id, + loadAlertInstanceSummary, + setAlertInstanceSummary, + toastNotifications + ); expect(toastNotifications.addDanger).toHaveBeenCalledTimes(1); expect(toastNotifications.addDanger).toHaveBeenCalledWith({ - title: 'Unable to load alert status: OMG', + title: 'Unable to load alert instance summary: OMG', }); }); }); function mockApis() { return { - loadAlertStatus: jest.fn(), + loadAlertInstanceSummary: jest.fn(), requestRefresh: jest.fn(), }; } function mockStateSetter() { return { - setAlertStatus: jest.fn(), + setAlertInstanceSummary: jest.fn(), }; } @@ -126,8 +136,8 @@ function mockAlert(overloads: Partial = {}): Alert { }; } -function mockAlertStatus(overloads: Partial = {}): any { - const status: AlertStatus = { +function mockAlertInstanceSummary(overloads: Partial = {}): any { + const summary: AlertInstanceSummary = { id: 'alert-id', name: 'alert-name', tags: ['tag-1', 'tag-2'], @@ -147,5 +157,5 @@ function mockAlertStatus(overloads: Partial = {}): any { }, }, }; - return status; + return summary; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.tsx index 3afec45bcad6..9137a26a32dd 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_details/components/alert_instances_route.tsx @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import { ToastsApi } from 'kibana/public'; import React, { useState, useEffect } from 'react'; import { EuiLoadingSpinner } from '@elastic/eui'; -import { Alert, AlertStatus } from '../../../../types'; +import { Alert, AlertInstanceSummary } from '../../../../types'; import { useAppDependencies } from '../../../app_context'; import { ComponentOpts as AlertApis, @@ -16,33 +16,40 @@ import { } from '../../common/components/with_bulk_alert_api_operations'; import { AlertInstancesWithApi as AlertInstances } from './alert_instances'; -type WithAlertStatusProps = { +type WithAlertInstanceSummaryProps = { alert: Alert; readOnly: boolean; requestRefresh: () => Promise; -} & Pick; +} & Pick; -export const AlertInstancesRoute: React.FunctionComponent = ({ +export const AlertInstancesRoute: React.FunctionComponent = ({ alert, readOnly, requestRefresh, - loadAlertStatus: loadAlertStatus, + loadAlertInstanceSummary: loadAlertInstanceSummary, }) => { const { toastNotifications } = useAppDependencies(); - const [alertStatus, setAlertStatus] = useState(null); + const [alertInstanceSummary, setAlertInstanceSummary] = useState( + null + ); useEffect(() => { - getAlertStatus(alert.id, loadAlertStatus, setAlertStatus, toastNotifications); + getAlertInstanceSummary( + alert.id, + loadAlertInstanceSummary, + setAlertInstanceSummary, + toastNotifications + ); // eslint-disable-next-line react-hooks/exhaustive-deps }, [alert]); - return alertStatus ? ( + return alertInstanceSummary ? ( ) : (
); }; -export async function getAlertStatus( +export async function getAlertInstanceSummary( alertId: string, - loadAlertStatus: AlertApis['loadAlertStatus'], - setAlertStatus: React.Dispatch>, + loadAlertInstanceSummary: AlertApis['loadAlertInstanceSummary'], + setAlertInstanceSummary: React.Dispatch>, toastNotifications: Pick ) { try { - const loadedStatus = await loadAlertStatus(alertId); - setAlertStatus(loadedStatus); + const loadedInstanceSummary = await loadAlertInstanceSummary(alertId); + setAlertInstanceSummary(loadedInstanceSummary); } catch (e) { toastNotifications.addDanger({ title: i18n.translate( - 'xpack.triggersActionsUI.sections.alertDetails.unableToLoadAlertStateMessage', + 'xpack.triggersActionsUI.sections.alertDetails.unableToLoadAlertInstanceSummaryMessage', { - defaultMessage: 'Unable to load alert status: {message}', + defaultMessage: 'Unable to load alert instance summary: {message}', values: { message: e.message, }, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx index 3803fcebbb92..8ac80c4ad288 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx @@ -11,7 +11,7 @@ import { EuiFormLabel } from '@elastic/eui'; import { coreMock } from '../../../../../../../src/core/public/mocks'; import AlertAdd from './alert_add'; import { actionTypeRegistryMock } from '../../action_type_registry.mock'; -import { ValidationResult } from '../../../types'; +import { Alert, ValidationResult } from '../../../types'; import { AlertsContextProvider, useAlertsContext } from '../../context/alerts_context'; import { alertTypeRegistryMock } from '../../alert_type_registry.mock'; import { chartPluginMock } from '../../../../../../../src/plugins/charts/public/mocks'; @@ -46,7 +46,7 @@ describe('alert_add', () => { let deps: any; let wrapper: ReactWrapper; - async function setup() { + async function setup(initialValues?: Partial) { const mocks = coreMock.createSetup(); const { loadAlertTypes } = jest.requireMock('../../lib/alert_api'); const alertTypes = [ @@ -155,6 +155,7 @@ describe('alert_add', () => { consumer={ALERTS_FEATURE_ID} addFlyoutVisible={true} setAddFlyoutVisibility={() => {}} + initialValues={initialValues} /> @@ -180,5 +181,31 @@ describe('alert_add', () => { wrapper.find('[data-test-subj="my-alert-type-SelectOption"]').first().simulate('click'); expect(wrapper.contains('Metadata: some value. Fields: test.')).toBeTruthy(); + + expect(wrapper.find('input#alertName').props().value).toBe(''); + + expect(wrapper.find('[data-test-subj="tagsComboBox"]').first().text()).toBe(''); + + expect(wrapper.find('.euiSelect').first().props().value).toBe('m'); + }); + + it('renders alert add flyout with initial values', async () => { + await setup({ + name: 'Simple status alert', + tags: ['uptime', 'logs'], + schedule: { + interval: '1h', + }, + }); + + await new Promise((resolve) => { + setTimeout(resolve, 1000); + }); + + expect(wrapper.find('input#alertName').props().value).toBe('Simple status alert'); + + expect(wrapper.find('[data-test-subj="tagsComboBox"]').first().text()).toBe('uptimelogs'); + + expect(wrapper.find('.euiSelect').first().props().value).toBe('h'); }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx index 20cbd42e34b6..97dcfec5ed3c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.tsx @@ -34,6 +34,7 @@ interface AlertAddProps { setAddFlyoutVisibility: React.Dispatch>; alertTypeId?: string; canChangeTrigger?: boolean; + initialValues?: Partial; } export const AlertAdd = ({ @@ -42,6 +43,7 @@ export const AlertAdd = ({ setAddFlyoutVisibility, canChangeTrigger, alertTypeId, + initialValues, }: AlertAddProps) => { const initialAlert = ({ params: {}, @@ -52,6 +54,7 @@ export const AlertAdd = ({ }, actions: [], tags: [], + ...(initialValues ? initialValues : {}), } as unknown) as Alert; const [{ alert }, dispatch] = useReducer(alertReducer, { alert: initialAlert }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx index fd8b35a96bdf..dc961482f182 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx @@ -10,7 +10,7 @@ import { Alert, AlertType, AlertTaskState, - AlertStatus, + AlertInstanceSummary, AlertingFrameworkHealth, } from '../../../../types'; import { useAppDependencies } from '../../../app_context'; @@ -28,7 +28,7 @@ import { unmuteAlertInstance, loadAlert, loadAlertState, - loadAlertStatus, + loadAlertInstanceSummary, loadAlertTypes, health, } from '../../../lib/alert_api'; @@ -58,7 +58,7 @@ export interface ComponentOpts { }>; loadAlert: (id: Alert['id']) => Promise; loadAlertState: (id: Alert['id']) => Promise; - loadAlertStatus: (id: Alert['id']) => Promise; + loadAlertInstanceSummary: (id: Alert['id']) => Promise; loadAlertTypes: () => Promise; getHealth: () => Promise; } @@ -127,7 +127,9 @@ export function withBulkAlertOperations( deleteAlert={async (alert: Alert) => deleteAlerts({ http, ids: [alert.id] })} loadAlert={async (alertId: Alert['id']) => loadAlert({ http, alertId })} loadAlertState={async (alertId: Alert['id']) => loadAlertState({ http, alertId })} - loadAlertStatus={async (alertId: Alert['id']) => loadAlertStatus({ http, alertId })} + loadAlertInstanceSummary={async (alertId: Alert['id']) => + loadAlertInstanceSummary({ http, alertId }) + } loadAlertTypes={async () => loadAlertTypes({ http })} getHealth={async () => health({ http })} /> diff --git a/x-pack/plugins/triggers_actions_ui/public/common/index.ts b/x-pack/plugins/triggers_actions_ui/public/common/index.ts index 9dd3fd787f86..8b728b5e178b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/common/index.ts @@ -7,3 +7,4 @@ export * from './expression_items'; export { connectorConfiguration as ServiceNowConnectorConfiguration } from '../application/components/builtin_action_types/servicenow/config'; +export { connectorConfiguration as JiraConnectorConfiguration } from '../application/components/builtin_action_types/jira/config'; diff --git a/x-pack/plugins/triggers_actions_ui/public/types.ts b/x-pack/plugins/triggers_actions_ui/public/types.ts index 0c0d99eed4e7..109d473c56e6 100644 --- a/x-pack/plugins/triggers_actions_ui/public/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/types.ts @@ -12,7 +12,7 @@ import { SanitizedAlert as Alert, AlertAction, AlertTaskState, - AlertStatus, + AlertInstanceSummary, AlertInstanceStatus, RawAlertInstance, AlertingFrameworkHealth, @@ -21,7 +21,7 @@ export { Alert, AlertAction, AlertTaskState, - AlertStatus, + AlertInstanceSummary, AlertInstanceStatus, RawAlertInstance, AlertingFrameworkHealth, @@ -54,6 +54,7 @@ export interface ActionParamsProps { messageVariables?: ActionVariable[]; defaultMessage?: string; docLinks: DocLinksStart; + actionConnector?: ActionConnector; } export interface Pagination { diff --git a/x-pack/plugins/uptime/common/constants/client_defaults.ts b/x-pack/plugins/uptime/common/constants/client_defaults.ts index d8a3ef8d7cbb..a5db67ae3b58 100644 --- a/x-pack/plugins/uptime/common/constants/client_defaults.ts +++ b/x-pack/plugins/uptime/common/constants/client_defaults.ts @@ -31,6 +31,7 @@ export const CLIENT_DEFAULTS = { * The end of the default date range is now. */ DATE_RANGE_END: 'now', + FOCUS_CONNECTOR_FIELD: false, FILTERS: '', MONITOR_LIST_PAGE_INDEX: 0, MONITOR_LIST_PAGE_SIZE: 20, diff --git a/x-pack/plugins/uptime/common/constants/plugin.ts b/x-pack/plugins/uptime/common/constants/plugin.ts index 6064524872a0..71bae9d8dafc 100644 --- a/x-pack/plugins/uptime/common/constants/plugin.ts +++ b/x-pack/plugins/uptime/common/constants/plugin.ts @@ -17,7 +17,6 @@ export const PLUGIN = { NAME: i18n.translate('xpack.uptime.featureRegistry.uptimeFeatureName', { defaultMessage: 'Uptime', }), - ROUTER_BASE_NAME: '/app/uptime#', TITLE: i18n.translate('xpack.uptime.uptimeFeatureCatalogueTitle', { defaultMessage: 'Uptime', }), diff --git a/x-pack/plugins/uptime/public/apps/plugin.ts b/x-pack/plugins/uptime/public/apps/plugin.ts index 9f7907ec3918..8a6699c16269 100644 --- a/x-pack/plugins/uptime/public/apps/plugin.ts +++ b/x-pack/plugins/uptime/public/apps/plugin.ts @@ -59,7 +59,7 @@ export class UptimePlugin title: PLUGIN.TITLE, description: PLUGIN.DESCRIPTION, icon: 'uptimeApp', - path: '/app/uptime#/', + path: '/app/uptime', showOnHomePage: false, category: FeatureCatalogueCategory.DATA, }); @@ -84,7 +84,6 @@ export class UptimePlugin }); core.application.register({ - appRoute: '/app/uptime#/', id: PLUGIN.ID, euiIconType: 'uptimeApp', order: 8400, diff --git a/x-pack/plugins/uptime/public/apps/render_app.tsx b/x-pack/plugins/uptime/public/apps/render_app.tsx index f834f8b5cdd3..c0567ff956ce 100644 --- a/x-pack/plugins/uptime/public/apps/render_app.tsx +++ b/x-pack/plugins/uptime/public/apps/render_app.tsx @@ -16,13 +16,12 @@ import { } from '../../common/constants'; import { UptimeApp, UptimeAppProps } from './uptime_app'; import { ClientPluginsSetup, ClientPluginsStart } from './plugin'; -import { PLUGIN } from '../../common/constants/plugin'; export function renderApp( core: CoreStart, plugins: ClientPluginsSetup, startPlugins: ClientPluginsStart, - { element }: AppMountParameters + { element, history }: AppMountParameters ) { const { application: { capabilities }, @@ -48,6 +47,7 @@ export function renderApp( basePath: basePath.get(), darkMode: core.uiSettings.get(DEFAULT_DARK_MODE), commonlyUsedRanges: core.uiSettings.get(DEFAULT_TIMEPICKER_QUICK_RANGES), + history, isApmAvailable: apm, isInfraAvailable: infrastructure, isLogsAvailable: logs, @@ -67,7 +67,6 @@ export function renderApp( }, ], }), - routerBasename: basePath.prepend(PLUGIN.ROUTER_BASE_NAME), setBadge, setBreadcrumbs: core.chrome.setBreadcrumbs, }; diff --git a/x-pack/plugins/uptime/public/apps/uptime_app.tsx b/x-pack/plugins/uptime/public/apps/uptime_app.tsx index 1dc34b44b7c6..4b58ba104314 100644 --- a/x-pack/plugins/uptime/public/apps/uptime_app.tsx +++ b/x-pack/plugins/uptime/public/apps/uptime_app.tsx @@ -8,7 +8,7 @@ import { EuiPage, EuiErrorBoundary } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useEffect } from 'react'; import { Provider as ReduxProvider } from 'react-redux'; -import { BrowserRouter as Router } from 'react-router-dom'; +import { Router } from 'react-router-dom'; import { I18nStart, ChromeBreadcrumb, CoreStart } from 'kibana/public'; import { KibanaContextProvider, @@ -31,6 +31,7 @@ import { } from '../components/overview/alerts'; import { store } from '../state'; import { kibanaService } from '../state/kibana_service'; +import { ScopedHistory } from '../../../../../src/core/public'; export interface UptimeAppColors { danger: string; @@ -46,13 +47,13 @@ export interface UptimeAppProps { canSave: boolean; core: CoreStart; darkMode: boolean; + history: ScopedHistory; i18n: I18nStart; isApmAvailable: boolean; isInfraAvailable: boolean; isLogsAvailable: boolean; plugins: ClientPluginsSetup; startPlugins: ClientPluginsStart; - routerBasename: string; setBadge: UMUpdateBadge; renderGlobalHelpControls(): void; commonlyUsedRanges: CommonlyUsedRange[]; @@ -68,7 +69,6 @@ const Application = (props: UptimeAppProps) => { i18n: i18nCore, plugins, renderGlobalHelpControls, - routerBasename, setBadge, startPlugins, } = props; @@ -99,7 +99,7 @@ const Application = (props: UptimeAppProps) => { - + diff --git a/x-pack/plugins/uptime/public/apps/uptime_overview_fetcher.ts b/x-pack/plugins/uptime/public/apps/uptime_overview_fetcher.ts index 7e5c18f13b29..b077f622c1de 100644 --- a/x-pack/plugins/uptime/public/apps/uptime_overview_fetcher.ts +++ b/x-pack/plugins/uptime/public/apps/uptime_overview_fetcher.ts @@ -24,7 +24,7 @@ async function fetchUptimeOverviewData({ const pings = await fetchPingHistogram({ dateStart: start, dateEnd: end, bucketSize }); const response: UptimeFetchDataResponse = { - appLink: `/app/uptime#/?dateRangeStart=${relativeTime.start}&dateRangeEnd=${relativeTime.end}`, + appLink: `/app/uptime?dateRangeStart=${relativeTime.start}&dateRangeEnd=${relativeTime.end}`, stats: { monitors: { type: 'number', diff --git a/x-pack/plugins/uptime/public/components/overview/empty_state/__tests__/__snapshots__/data_or_index_missing.test.tsx.snap b/x-pack/plugins/uptime/public/components/overview/empty_state/__tests__/__snapshots__/data_or_index_missing.test.tsx.snap index 0429d36bf874..41e46259715e 100644 --- a/x-pack/plugins/uptime/public/components/overview/empty_state/__tests__/__snapshots__/data_or_index_missing.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/overview/empty_state/__tests__/__snapshots__/data_or_index_missing.test.tsx.snap @@ -36,7 +36,7 @@ exports[`DataOrIndexMissing component renders headingMessage 1`] = ` - + Get https://expired.badssl.com: x509: certificate has expired or is not yet valid diff --git a/x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx b/x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx index d688660f564c..9b9af2028530 100644 --- a/x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx +++ b/x-pack/plugins/uptime/public/hooks/__tests__/use_breadcrumbs.test.tsx @@ -44,7 +44,11 @@ describe('useBreadcrumbs', () => { ); const urlParams: UptimeUrlParams = getSupportedUrlParams({}); - expect(getBreadcrumbs()).toStrictEqual([makeBaseBreadcrumb(urlParams)].concat(expectedCrumbs)); + expect(JSON.stringify(getBreadcrumbs())).toEqual( + JSON.stringify( + [makeBaseBreadcrumb('/app/uptime', jest.fn(), urlParams)].concat(expectedCrumbs) + ) + ); }); }); @@ -54,6 +58,10 @@ const mockCore: () => [() => ChromeBreadcrumb[], any] = () => { return breadcrumbObj; }; const core = { + application: { + getUrlForApp: () => '/app/uptime', + navigateToUrl: jest.fn(), + }, chrome: { setBreadcrumbs: (newBreadcrumbs: ChromeBreadcrumb[]) => { breadcrumbObj = newBreadcrumbs; diff --git a/x-pack/plugins/uptime/public/hooks/use_breadcrumbs.ts b/x-pack/plugins/uptime/public/hooks/use_breadcrumbs.ts index 182c6b011412..ddd3ca7c4f52 100644 --- a/x-pack/plugins/uptime/public/hooks/use_breadcrumbs.ts +++ b/x-pack/plugins/uptime/public/hooks/use_breadcrumbs.ts @@ -7,35 +7,52 @@ import { ChromeBreadcrumb } from 'kibana/public'; import { i18n } from '@kbn/i18n'; import { useEffect } from 'react'; +import { EuiBreadcrumb } from '@elastic/eui'; import { UptimeUrlParams } from '../lib/helper'; import { stringifyUrlParams } from '../lib/helper/stringify_url_params'; import { useKibana } from '../../../../../src/plugins/kibana_react/public'; import { useUrlParams } from '.'; +import { PLUGIN } from '../../common/constants/plugin'; -export const makeBaseBreadcrumb = (params?: UptimeUrlParams): ChromeBreadcrumb => { - let href = '#/'; +const EMPTY_QUERY = '?'; + +export const makeBaseBreadcrumb = ( + href: string, + navigateToHref?: (url: string) => Promise, + params?: UptimeUrlParams +): EuiBreadcrumb => { if (params) { const crumbParams: Partial = { ...params }; // We don't want to encode this values because they are often set to Date.now(), the relative // values in dateRangeStart are better for a URL. delete crumbParams.absoluteDateRangeStart; delete crumbParams.absoluteDateRangeEnd; - href += stringifyUrlParams(crumbParams, true); + const query = stringifyUrlParams(crumbParams, true); + href += query === EMPTY_QUERY ? '' : query; } return { text: i18n.translate('xpack.uptime.breadcrumbs.overviewBreadcrumbText', { defaultMessage: 'Uptime', }), href, + onClick: (event) => { + if (href && navigateToHref) { + event.preventDefault(); + navigateToHref(href); + } + }, }; }; export const useBreadcrumbs = (extraCrumbs: ChromeBreadcrumb[]) => { const params = useUrlParams()[0](); - const setBreadcrumbs = useKibana().services.chrome?.setBreadcrumbs; + const kibana = useKibana(); + const setBreadcrumbs = kibana.services.chrome?.setBreadcrumbs; + const appPath = kibana.services.application?.getUrlForApp(PLUGIN.ID) ?? ''; + const navigate = kibana.services.application?.navigateToUrl; useEffect(() => { if (setBreadcrumbs) { - setBreadcrumbs([makeBaseBreadcrumb(params)].concat(extraCrumbs)); + setBreadcrumbs([makeBaseBreadcrumb(appPath, navigate, params)].concat(extraCrumbs)); } - }, [extraCrumbs, params, setBreadcrumbs]); + }, [appPath, extraCrumbs, navigate, params, setBreadcrumbs]); }; diff --git a/x-pack/plugins/uptime/public/lib/helper/__tests__/__snapshots__/stringify_url_params.test.ts.snap b/x-pack/plugins/uptime/public/lib/helper/__tests__/__snapshots__/stringify_url_params.test.ts.snap deleted file mode 100644 index 31f5ceff7d04..000000000000 --- a/x-pack/plugins/uptime/public/lib/helper/__tests__/__snapshots__/stringify_url_params.test.ts.snap +++ /dev/null @@ -1,5 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`stringifyUrlParams creates expected string value 1`] = `"?autorefreshInterval=50000&autorefreshIsPaused=false&dateRangeStart=now-15m&dateRangeEnd=now&filters=monitor.id%3A%20bar&search=monitor.id%3A%20foo&selectedPingStatus=down&statusFilter=up"`; - -exports[`stringifyUrlParams creates expected string value when ignore empty is true 1`] = `"?autorefreshInterval=50000&filters=monitor.id%3A%20bar"`; diff --git a/x-pack/plugins/uptime/public/lib/helper/__tests__/stringify_url_params.test.ts b/x-pack/plugins/uptime/public/lib/helper/__tests__/stringify_url_params.test.ts index a2f9b29c4ff5..8cf35c728fc0 100644 --- a/x-pack/plugins/uptime/public/lib/helper/__tests__/stringify_url_params.test.ts +++ b/x-pack/plugins/uptime/public/lib/helper/__tests__/stringify_url_params.test.ts @@ -14,11 +14,14 @@ describe('stringifyUrlParams', () => { dateRangeStart: 'now-15m', dateRangeEnd: 'now', filters: 'monitor.id: bar', + focusConnectorField: true, search: 'monitor.id: foo', selectedPingStatus: 'down', statusFilter: 'up', }); - expect(result).toMatchSnapshot(); + expect(result).toMatchInlineSnapshot( + `"?autorefreshInterval=50000&autorefreshIsPaused=false&dateRangeStart=now-15m&dateRangeEnd=now&filters=monitor.id%3A%20bar&focusConnectorField=true&search=monitor.id%3A%20foo&selectedPingStatus=down&statusFilter=up"` + ); }); it('creates expected string value when ignore empty is true', () => { @@ -29,6 +32,7 @@ describe('stringifyUrlParams', () => { dateRangeStart: 'now-15m', dateRangeEnd: 'now', filters: 'monitor.id: bar', + focusConnectorField: false, search: undefined, selectedPingStatus: undefined, statusFilter: '', @@ -36,7 +40,9 @@ describe('stringifyUrlParams', () => { }, true ); - expect(result).toMatchSnapshot(); + expect(result).toMatchInlineSnapshot( + `"?autorefreshInterval=50000&filters=monitor.id%3A%20bar"` + ); expect(result.includes('pagination')).toBeFalsy(); expect(result.includes('search')).toBeFalsy(); diff --git a/x-pack/plugins/uptime/public/lib/helper/stringify_url_params.ts b/x-pack/plugins/uptime/public/lib/helper/stringify_url_params.ts index a8ce86c4399e..b10af1596140 100644 --- a/x-pack/plugins/uptime/public/lib/helper/stringify_url_params.ts +++ b/x-pack/plugins/uptime/public/lib/helper/stringify_url_params.ts @@ -13,6 +13,7 @@ const { AUTOREFRESH_IS_PAUSED, DATE_RANGE_START, DATE_RANGE_END, + FOCUS_CONNECTOR_FIELD, } = CLIENT_DEFAULTS; export const stringifyUrlParams = (params: Partial, ignoreEmpty = false) => { @@ -36,6 +37,9 @@ export const stringifyUrlParams = (params: Partial, ignoreEmpty if (key === 'autorefreshInterval' && val === AUTOREFRESH_INTERVAL) { delete params[key]; } + if (key === 'focusConnectorField' && val === FOCUS_CONNECTOR_FIELD) { + delete params[key]; + } }); } return `?${stringify(params, { sort: false })}`; diff --git a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/watch_visualization.tsx b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/watch_visualization.tsx index 2ff0f53d07e9..935f0209e73c 100644 --- a/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/watch_visualization.tsx +++ b/x-pack/plugins/watcher/public/application/sections/watch_edit/components/threshold_watch_edit/watch_visualization.tsx @@ -126,7 +126,7 @@ export const WatchVisualization = () => { isLoading, data: watchVisualizationData, error, - sendRequest: reload, + resendRequest: reload, } = useGetWatchVisualizationData(watchWithoutActions, visualizeOptions); useEffect( diff --git a/x-pack/test/accessibility/apps/spaces.ts b/x-pack/test/accessibility/apps/spaces.ts new file mode 100644 index 000000000000..e11de1376e40 --- /dev/null +++ b/x-pack/test/accessibility/apps/spaces.ts @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +// a11y tests for spaces, space selection and spacce creation and feature controls + +import { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const PageObjects = getPageObjects(['common', 'spaceSelector', 'home', 'header', 'security']); + const a11y = getService('a11y'); + const browser = getService('browser'); + const esArchiver = getService('esArchiver'); + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + const toasts = getService('toasts'); + + describe('Kibana spaces page meets a11y validations', () => { + before(async () => { + await esArchiver.load('empty_kibana'); + await PageObjects.common.navigateToApp('home'); + }); + + it('a11y test for manage spaces menu from top nav on Kibana home', async () => { + await PageObjects.spaceSelector.openSpacesNav(); + await retry.waitFor( + 'Manage spaces option visible', + async () => await testSubjects.exists('manageSpaces') + ); + await a11y.testAppSnapshot(); + }); + + it('a11y test for manage spaces page', async () => { + await PageObjects.spaceSelector.clickManageSpaces(); + await PageObjects.header.waitUntilLoadingHasFinished(); + await toasts.dismissAllToasts(); + await retry.waitFor( + 'Manage spaces page visible', + async () => await testSubjects.exists('createSpace') + ); + await a11y.testAppSnapshot(); + }); + + it('a11y test for click on create space page', async () => { + await PageObjects.spaceSelector.clickCreateSpace(); + await a11y.testAppSnapshot(); + }); + + it('a11y test for for customize space card', async () => { + await PageObjects.spaceSelector.clickEnterSpaceName(); + await PageObjects.spaceSelector.addSpaceName('space_a'); + await PageObjects.spaceSelector.clickSpaceAcustomAvatar(); + await a11y.testAppSnapshot(); + await browser.pressKeys(browser.keys.ESCAPE); + }); + + // EUI issue - https://github.com/elastic/eui/issues/3999 + it.skip('a11y test for color picker', async () => { + await PageObjects.spaceSelector.clickColorPicker(); + await a11y.testAppSnapshot(); + await browser.pressKeys(browser.keys.ESCAPE); + }); + + it('a11y test for customize and reset space URL identifier', async () => { + await PageObjects.spaceSelector.clickOnCustomizeURL(); + await a11y.testAppSnapshot(); + await PageObjects.spaceSelector.clickOnCustomizeURL(); + await a11y.testAppSnapshot(); + }); + + it('a11y test for describe space text space', async () => { + await PageObjects.spaceSelector.clickOnDescriptionOfSpace(); + await a11y.testAppSnapshot(); + }); + + it('a11y test for click on "show" button to open customize feature display', async () => { + await retry.waitFor( + 'show button is visible', + async () => await testSubjects.exists('show-hide-section-link') + ); + await PageObjects.spaceSelector.clickShowFeatures(); + await a11y.testAppSnapshot(); + }); + + it('a11y test for change all option for feature visibility popover', async () => { + await PageObjects.spaceSelector.clickFeaturesVisibilityButton(); + await a11y.testAppSnapshot(); + }); + + it('a11y test for hide all feature visibility popover option', async () => { + await PageObjects.spaceSelector.clickHideAllFeatures(); + await a11y.testAppSnapshot(); + }); + + it('a11y test for toggle individual feature - using enterprise feature visibility', async () => { + await PageObjects.spaceSelector.clickFeaturesVisibilityButton(); + await PageObjects.spaceSelector.clickShowAllFeatures(); + await PageObjects.spaceSelector.toggleFeatureVisibility('enterpriseSearch'); + await a11y.testAppSnapshot(); + }); + + it('a11y test for space listing page', async () => { + await PageObjects.spaceSelector.clickSaveSpaceCreation(); + await a11y.testAppSnapshot(); + }); + + it('a11y test for updating a space', async () => { + await PageObjects.spaceSelector.clickSpaceEditButton('space_a'); + await a11y.testAppSnapshot(); + await PageObjects.spaceSelector.clickCancelSpaceCreation(); + }); + + // creating space b and making it the current space so space selector page gets displayed when space b gets deleted + it('a11y test for delete space button', async () => { + await PageObjects.spaceSelector.clickCreateSpace(); + await PageObjects.spaceSelector.clickEnterSpaceName(); + await PageObjects.spaceSelector.addSpaceName('space_b'); + await PageObjects.spaceSelector.clickSaveSpaceCreation(); + await PageObjects.common.navigateToApp('home'); + await PageObjects.spaceSelector.openSpacesNav(); + await PageObjects.spaceSelector.clickSpaceAvatar('space_b'); + await PageObjects.header.waitUntilLoadingHasFinished(); + await PageObjects.spaceSelector.openSpacesNav(); + await PageObjects.spaceSelector.clickManageSpaces(); + await PageObjects.spaceSelector.clickOnDeleteSpaceButton('space_b'); + await a11y.testAppSnapshot(); + // a11y test for no space name in confirm dialogue box + await PageObjects.spaceSelector.confirmDeletingSpace(); + await a11y.testAppSnapshot(); + }); + + // test starts with deleting space b so we can get the space selection page instead of logging out in the test + it('a11y test for space selection page', async () => { + await PageObjects.spaceSelector.setSpaceNameTobeDeleted('space_b'); + await PageObjects.spaceSelector.confirmDeletingSpace(); + await a11y.testAppSnapshot(); + await PageObjects.spaceSelector.clickSpaceCard('default'); + }); + }); +} diff --git a/x-pack/test/accessibility/config.ts b/x-pack/test/accessibility/config.ts index 0a9580575431..bae7b688fd28 100644 --- a/x-pack/test/accessibility/config.ts +++ b/x-pack/test/accessibility/config.ts @@ -20,7 +20,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('./apps/grok_debugger'), require.resolve('./apps/search_profiler'), require.resolve('./apps/uptime'), - require.resolve('./apps/painless_lab'), + require.resolve('./apps/spaces'), ], pageObjects, services, diff --git a/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/jira.ts b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/jira.ts new file mode 100644 index 000000000000..025fd558ee1c --- /dev/null +++ b/x-pack/test/alerting_api_integration/basic/tests/actions/builtin_action_types/jira.ts @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FtrProviderContext } from '../../../../common/ftr_provider_context'; + +import { + getExternalServiceSimulatorPath, + ExternalServiceSimulator, +} from '../../../../common/fixtures/plugins/actions_simulators/server/plugin'; + +// node ../scripts/functional_test_runner.js --grep "Actions.servicenddd" --config=test/alerting_api_integration/security_and_spaces/config.ts + +const mapping = [ + { + source: 'title', + target: 'summary', + actionType: 'nothing', + }, + { + source: 'description', + target: 'description', + actionType: 'nothing', + }, + { + source: 'comments', + target: 'comments', + actionType: 'nothing', + }, +]; + +// eslint-disable-next-line import/no-default-export +export default function jiraTest({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const kibanaServer = getService('kibanaServer'); + const mockJira = { + config: { + apiUrl: 'www.jiraisinkibanaactions.com', + incidentConfiguration: { mapping: [...mapping] }, + isCaseOwned: true, + }, + secrets: { + email: 'elastic', + apiToken: 'changeme', + }, + params: { + savedObjectId: '123', + title: 'a title', + description: 'a description', + labels: ['kibana'], + issueType: '10006', + priority: 'High', + externalId: null, + comments: [ + { + commentId: '456', + comment: 'first comment', + }, + ], + }, + }; + describe('jira', () => { + let jiraSimulatorURL: string = ''; + + // need to wait for kibanaServer to settle ... + before(() => { + jiraSimulatorURL = kibanaServer.resolveUrl( + getExternalServiceSimulatorPath(ExternalServiceSimulator.JIRA) + ); + }); + + it('should return 403 when creating a jira action', async () => { + await supertest + .post('/api/actions/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A jira action', + actionTypeId: '.jira', + config: { + apiUrl: jiraSimulatorURL, + projectKey: 'CK', + incidentConfiguration: { ...mockJira.config.incidentConfiguration }, + isCaseOwned: true, + }, + secrets: mockJira.secrets, + }) + .expect(403, { + statusCode: 403, + error: 'Forbidden', + message: + 'Action type .jira is disabled because your basic license does not support it. Please upgrade your license.', + }); + }); + }); +} diff --git a/x-pack/test/alerting_api_integration/basic/tests/actions/index.ts b/x-pack/test/alerting_api_integration/basic/tests/actions/index.ts index 1788a12afebf..8f31e7f96b56 100644 --- a/x-pack/test/alerting_api_integration/basic/tests/actions/index.ts +++ b/x-pack/test/alerting_api_integration/basic/tests/actions/index.ts @@ -11,6 +11,7 @@ export default function actionsTests({ loadTestFile }: FtrProviderContext) { describe('Actions', () => { loadTestFile(require.resolve('./builtin_action_types/email')); loadTestFile(require.resolve('./builtin_action_types/es_index')); + loadTestFile(require.resolve('./builtin_action_types/jira')); loadTestFile(require.resolve('./builtin_action_types/pagerduty')); loadTestFile(require.resolve('./builtin_action_types/server_log')); loadTestFile(require.resolve('./builtin_action_types/servicenow')); diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/jira_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/jira_simulation.ts index 4b65b7a8f263..6041251dc28a 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/jira_simulation.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/jira_simulation.ts @@ -105,6 +105,57 @@ export function initPlugin(router: IRouter, path: string) { }); } ); + + router.get( + { + path: `${path}/rest/capabilities`, + options: { + authRequired: false, + }, + validate: {}, + }, + async function ( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + return jsonResponse(res, 200, { + capabilities: {}, + }); + } + ); + + router.get( + { + path: `${path}/rest/api/2/issue/createmeta`, + options: { + authRequired: false, + }, + validate: {}, + }, + async function ( + context: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise> { + return jsonResponse(res, 200, { + projects: [ + { + issuetypes: [ + { + id: '10006', + name: 'Task', + }, + { + id: '10007', + name: 'Sub-task', + }, + ], + }, + ], + }); + } + ); } function jsonResponse( diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts index 0f7acf5ead1a..88f0f02794c9 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/server/plugin.ts @@ -38,6 +38,7 @@ export function getAllExternalServiceSimulatorPaths(): string[] { ); allPaths.push(`/api/_${NAME}/${ExternalServiceSimulator.SERVICENOW}/api/now/v2/table/incident`); allPaths.push(`/api/_${NAME}/${ExternalServiceSimulator.JIRA}/rest/api/2/issue`); + allPaths.push(`/api/_${NAME}/${ExternalServiceSimulator.JIRA}/rest/api/2/createmeta`); allPaths.push(`/api/_${NAME}/${ExternalServiceSimulator.RESILIENT}/rest/orgs/201/incidents`); return allPaths; } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts index 3ffd58b945dd..84fad699525a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts @@ -43,7 +43,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { config: { apiUrl: 'www.jiraisinkibanaactions.com', projectKey: 'CK', - casesConfiguration: { mapping }, + incidentConfiguration: { mapping }, }, secrets: { apiToken: 'elastic', @@ -94,6 +94,8 @@ export default function jiraTest({ getService }: FtrProviderContext) { config: { ...mockJira.config, apiUrl: jiraSimulatorURL, + incidentConfiguration: mockJira.config.incidentConfiguration, + isCaseOwned: true, }, secrets: mockJira.secrets, }) @@ -107,7 +109,8 @@ export default function jiraTest({ getService }: FtrProviderContext) { config: { apiUrl: jiraSimulatorURL, projectKey: mockJira.config.projectKey, - casesConfiguration: mockJira.config.casesConfiguration, + incidentConfiguration: mockJira.config.incidentConfiguration, + isCaseOwned: true, }, }); @@ -123,7 +126,8 @@ export default function jiraTest({ getService }: FtrProviderContext) { config: { apiUrl: jiraSimulatorURL, projectKey: mockJira.config.projectKey, - casesConfiguration: mockJira.config.casesConfiguration, + incidentConfiguration: mockJira.config.incidentConfiguration, + isCaseOwned: true, }, }); }); @@ -178,7 +182,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { config: { apiUrl: 'http://jira.mynonexistent.com', projectKey: mockJira.config.projectKey, - casesConfiguration: mockJira.config.casesConfiguration, + incidentConfiguration: mockJira.config.incidentConfiguration, }, secrets: mockJira.secrets, }) @@ -203,7 +207,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { config: { apiUrl: jiraSimulatorURL, projectKey: mockJira.config.projectKey, - casesConfiguration: mockJira.config.casesConfiguration, + incidentConfiguration: mockJira.config.incidentConfiguration, }, }) .expect(400) @@ -217,30 +221,6 @@ export default function jiraTest({ getService }: FtrProviderContext) { }); }); - it('should respond with a 400 Bad Request when creating a jira action without casesConfiguration', async () => { - await supertest - .post('/api/actions/action') - .set('kbn-xsrf', 'foo') - .send({ - name: 'A jira action', - actionTypeId: '.jira', - config: { - apiUrl: jiraSimulatorURL, - projectKey: mockJira.config.projectKey, - }, - secrets: mockJira.secrets, - }) - .expect(400) - .then((resp: any) => { - expect(resp.body).to.eql({ - statusCode: 400, - error: 'Bad Request', - message: - 'error validating action type config: [casesConfiguration.mapping]: expected value of type [array] but got [undefined]', - }); - }); - }); - it('should respond with a 400 Bad Request when creating a jira action with empty mapping', async () => { await supertest .post('/api/actions/action') @@ -251,7 +231,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { config: { apiUrl: jiraSimulatorURL, projectKey: mockJira.config.projectKey, - casesConfiguration: { mapping: [] }, + incidentConfiguration: { mapping: [] }, }, secrets: mockJira.secrets, }) @@ -261,7 +241,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { statusCode: 400, error: 'Bad Request', message: - 'error validating action type config: [casesConfiguration.mapping]: expected non-empty but got empty', + 'error validating action type config: [incidentConfiguration.mapping]: expected non-empty but got empty', }); }); }); @@ -276,7 +256,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { config: { apiUrl: jiraSimulatorURL, projectKey: mockJira.config.projectKey, - casesConfiguration: { + incidentConfiguration: { mapping: [ { source: 'title', @@ -307,7 +287,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { config: { apiUrl: jiraSimulatorURL, projectKey: mockJira.config.projectKey, - casesConfiguration: mockJira.config.casesConfiguration, + incidentConfiguration: mockJira.config.incidentConfiguration, }, secrets: mockJira.secrets, }); @@ -353,7 +333,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subAction]: expected value to equal [pushToService]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subAction]: expected value to equal [pushToService]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]', }); }); }); @@ -371,7 +351,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.savedObjectId]: expected value of type [string] but got [undefined]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.savedObjectId]: expected value of type [string] but got [undefined]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]', }); }); }); @@ -389,7 +369,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.savedObjectId]: expected value of type [string] but got [undefined]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.savedObjectId]: expected value of type [string] but got [undefined]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]', }); }); }); @@ -412,31 +392,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]', - }); - }); - }); - - it('should handle failing with a simulated success without createdAt', async () => { - await supertest - .post(`/api/actions/action/${simulatedActionId}/_execute`) - .set('kbn-xsrf', 'foo') - .send({ - params: { - ...mockJira.params, - subActionParams: { - savedObjectId: 'success', - title: 'success', - }, - }, - }) - .then((resp: any) => { - expect(resp.body).to.eql({ - actionId: simulatedActionId, - status: 'error', - retry: false, - message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.createdAt]: expected value of type [string] but got [undefined]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]', }); }); }); @@ -464,7 +420,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]', }); }); }); @@ -492,35 +448,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { status: 'error', retry: false, message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]', - }); - }); - }); - - it('should handle failing with a simulated success without comment.createdAt', async () => { - await supertest - .post(`/api/actions/action/${simulatedActionId}/_execute`) - .set('kbn-xsrf', 'foo') - .send({ - params: { - ...mockJira.params, - subActionParams: { - ...mockJira.params.subActionParams, - savedObjectId: 'success', - title: 'success', - createdAt: 'success', - createdBy: { username: 'elastic' }, - comments: [{ commentId: 'success', comment: 'success' }], - }, - }, - }) - .then((resp: any) => { - expect(resp.body).to.eql({ - actionId: simulatedActionId, - status: 'error', - retry: false, - message: - 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.createdAt]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]', + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]\n- [3.subAction]: expected value to equal [issueTypes]\n- [4.subAction]: expected value to equal [fieldsByIssueType]', }); }); }); @@ -537,6 +465,7 @@ export default function jiraTest({ getService }: FtrProviderContext) { subActionParams: { ...mockJira.params.subActionParams, comments: [], + issueType: '10006', }, }, }) diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_status.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_instance_summary.ts similarity index 90% rename from x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_status.ts rename to x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_instance_summary.ts index b700b5fb40b6..c8148f0c7a87 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_status.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/get_alert_instance_summary.ts @@ -17,11 +17,11 @@ import { FtrProviderContext } from '../../../common/ftr_provider_context'; import { UserAtSpaceScenarios } from '../../scenarios'; // eslint-disable-next-line import/no-default-export -export default function createGetAlertStatusTests({ getService }: FtrProviderContext) { +export default function createGetAlertInstanceSummaryTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); - describe('getAlertStatus', () => { + describe('getAlertInstanceSummary', () => { const objectRemover = new ObjectRemover(supertest); afterEach(() => objectRemover.removeAll()); @@ -29,7 +29,7 @@ export default function createGetAlertStatusTests({ getService }: FtrProviderCon for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; describe(scenario.id, () => { - it('should handle getAlertStatus alert request appropriately', async () => { + it('should handle getAlertInstanceSummary alert request appropriately', async () => { const { body: createdAlert } = await supertest .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) .set('kbn-xsrf', 'foo') @@ -38,7 +38,7 @@ export default function createGetAlertStatusTests({ getService }: FtrProviderCon objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/status`) + .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary`) .auth(user.username, user.password); switch (scenario.id) { @@ -85,7 +85,7 @@ export default function createGetAlertStatusTests({ getService }: FtrProviderCon } }); - it('should handle getAlertStatus alert request appropriately when unauthorized', async () => { + it('should handle getAlertInstanceSummary alert request appropriately when unauthorized', async () => { const { body: createdAlert } = await supertest .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) .set('kbn-xsrf', 'foo') @@ -99,7 +99,7 @@ export default function createGetAlertStatusTests({ getService }: FtrProviderCon objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/status`) + .get(`${getUrlPrefix(space.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary`) .auth(user.username, user.password); switch (scenario.id) { @@ -140,7 +140,7 @@ export default function createGetAlertStatusTests({ getService }: FtrProviderCon } }); - it(`shouldn't getAlertStatus for an alert from another space`, async () => { + it(`shouldn't getAlertInstanceSummary for an alert from another space`, async () => { const { body: createdAlert } = await supertest .post(`${getUrlPrefix(space.id)}/api/alerts/alert`) .set('kbn-xsrf', 'foo') @@ -149,7 +149,7 @@ export default function createGetAlertStatusTests({ getService }: FtrProviderCon objectRemover.add(space.id, createdAlert.id, 'alert', 'alerts'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix('other')}/api/alerts/alert/${createdAlert.id}/status`) + .get(`${getUrlPrefix('other')}/api/alerts/alert/${createdAlert.id}/_instance_summary`) .auth(user.username, user.password); expect(response.statusCode).to.eql(404); @@ -172,9 +172,9 @@ export default function createGetAlertStatusTests({ getService }: FtrProviderCon } }); - it(`should handle getAlertStatus request appropriately when alert doesn't exist`, async () => { + it(`should handle getAlertInstanceSummary request appropriately when alert doesn't exist`, async () => { const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerts/alert/1/status`) + .get(`${getUrlPrefix(space.id)}/api/alerts/alert/1/_instance_summary`) .auth(user.username, user.password); switch (scenario.id) { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts index 45fa075a6597..b03a3c8ccf6a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/index.ts @@ -16,7 +16,7 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./enable')); loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./get_alert_state')); - loadTestFile(require.resolve('./get_alert_status')); + loadTestFile(require.resolve('./get_alert_instance_summary')); loadTestFile(require.resolve('./list_alert_types')); loadTestFile(require.resolve('./mute_all')); loadTestFile(require.resolve('./mute_instance')); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_status.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_instance_summary.ts similarity index 95% rename from x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_status.ts rename to x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_instance_summary.ts index 341313ce55c6..563127e028a6 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_status.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_alert_instance_summary.ts @@ -18,20 +18,20 @@ import { import { FtrProviderContext } from '../../../common/ftr_provider_context'; // eslint-disable-next-line import/no-default-export -export default function createGetAlertStatusTests({ getService }: FtrProviderContext) { +export default function createGetAlertInstanceSummaryTests({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const supertestWithoutAuth = getService('supertestWithoutAuth'); const retry = getService('retry'); const alertUtils = new AlertUtils({ space: Spaces.space1, supertestWithoutAuth }); - describe('getAlertStatus', () => { + describe('getAlertInstanceSummary', () => { const objectRemover = new ObjectRemover(supertest); afterEach(() => objectRemover.removeAll()); it(`handles non-existant alert`, async () => { await supertest - .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/1/status`) + .get(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/1/_instance_summary`) .expect(404, { statusCode: 404, error: 'Not Found', @@ -49,7 +49,7 @@ export default function createGetAlertStatusTests({ getService }: FtrProviderCon await waitForEvents(createdAlert.id, ['execute']); const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/status` + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary` ); expect(response.status).to.eql(200); @@ -82,7 +82,7 @@ export default function createGetAlertStatusTests({ getService }: FtrProviderCon objectRemover.add(Spaces.space1.id, createdAlert.id, 'alert', 'alerts'); const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/status` + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary` ); expect(response.status).to.eql(200); @@ -119,7 +119,7 @@ export default function createGetAlertStatusTests({ getService }: FtrProviderCon const response = await supertest.get( `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${ createdAlert.id - }/status?dateStart=${dateStart}` + }/_instance_summary?dateStart=${dateStart}` ); expect(response.status).to.eql(200); const { statusStartDate, statusEndDate } = response.body; @@ -140,7 +140,7 @@ export default function createGetAlertStatusTests({ getService }: FtrProviderCon const response = await supertest.get( `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${ createdAlert.id - }/status?dateStart=${dateStart}` + }/_instance_summary?dateStart=${dateStart}` ); expect(response.status).to.eql(400); expect(response.body).to.eql({ @@ -161,7 +161,7 @@ export default function createGetAlertStatusTests({ getService }: FtrProviderCon await alertUtils.muteInstance(createdAlert.id, '1'); await waitForEvents(createdAlert.id, ['execute']); const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/status` + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary` ); expect(response.status).to.eql(200); @@ -184,7 +184,7 @@ export default function createGetAlertStatusTests({ getService }: FtrProviderCon await waitForEvents(createdAlert.id, ['execute']); const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/status` + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary` ); const { errorMessages } = response.body; expect(errorMessages.length).to.be.greaterThan(0); @@ -218,7 +218,7 @@ export default function createGetAlertStatusTests({ getService }: FtrProviderCon await alertUtils.muteInstance(createdAlert.id, 'instanceD'); await waitForEvents(createdAlert.id, ['new-instance', 'resolved-instance']); const response = await supertest.get( - `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/status` + `${getUrlPrefix(Spaces.space1.id)}/api/alerts/alert/${createdAlert.id}/_instance_summary` ); const actualInstances = response.body.instances; diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts index 78ca2af12ec3..3a3fed22f020 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/index.ts @@ -16,7 +16,7 @@ export default function alertingTests({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./find')); loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./get_alert_state')); - loadTestFile(require.resolve('./get_alert_status')); + loadTestFile(require.resolve('./get_alert_instance_summary')); loadTestFile(require.resolve('./list_alert_types')); loadTestFile(require.resolve('./event_log')); loadTestFile(require.resolve('./mute_all')); diff --git a/x-pack/test/api_integration/apis/lens/field_stats.ts b/x-pack/test/api_integration/apis/lens/field_stats.ts index 87c9d97be9b6..ccaea03691f0 100644 --- a/x-pack/test/api_integration/apis/lens/field_stats.ts +++ b/x-pack/test/api_integration/apis/lens/field_stats.ts @@ -279,6 +279,139 @@ export default ({ getService }: FtrProviderContext) => { }); }); + it('should return top values for ip fields', async () => { + const { body } = await supertest + .post('/api/lens/index_stats/logstash-2015.09.22/field') + .set(COMMON_HEADERS) + .send({ + dslQuery: { match_all: {} }, + fromDate: TEST_START_TIME, + toDate: TEST_END_TIME, + timeFieldName: '@timestamp', + field: { + name: 'ip', + type: 'ip', + }, + }) + .expect(200); + + expect(body).to.eql({ + totalDocuments: 4634, + sampledDocuments: 4634, + sampledValues: 4633, + topValues: { + buckets: [ + { + count: 13, + key: '177.194.175.66', + }, + { + count: 12, + key: '18.55.141.62', + }, + { + count: 12, + key: '53.55.251.105', + }, + { + count: 11, + key: '21.111.249.239', + }, + { + count: 11, + key: '97.63.84.25', + }, + { + count: 11, + key: '100.99.207.174', + }, + { + count: 11, + key: '112.34.138.226', + }, + { + count: 11, + key: '194.68.89.92', + }, + { + count: 11, + key: '235.186.79.201', + }, + { + count: 10, + key: '57.79.108.136', + }, + ], + }, + }); + }); + + it('should return histograms for scripted date fields', async () => { + const { body } = await supertest + .post('/api/lens/index_stats/logstash-2015.09.22/field') + .set(COMMON_HEADERS) + .send({ + dslQuery: { match_all: {} }, + fromDate: TEST_START_TIME, + toDate: TEST_END_TIME, + timeFieldName: '@timestamp', + field: { + name: 'scripted date', + type: 'date', + scripted: true, + script: '1234', + lang: 'painless', + }, + }) + .expect(200); + + expect(body).to.eql({ + histogram: { + buckets: [ + { + count: 4634, + key: 0, + }, + ], + }, + totalDocuments: 4634, + }); + }); + + it('should return top values for scripted string fields', async () => { + const { body } = await supertest + .post('/api/lens/index_stats/logstash-2015.09.22/field') + .set(COMMON_HEADERS) + .send({ + dslQuery: { match_all: {} }, + fromDate: TEST_START_TIME, + toDate: TEST_END_TIME, + timeFieldName: '@timestamp', + field: { + name: 'scripted string', + type: 'string', + scripted: true, + script: 'return "hello"', + lang: 'painless', + }, + }) + .expect(200); + + expect(body).to.eql({ + totalDocuments: 4634, + sampledDocuments: 4634, + sampledValues: 4634, + topValues: { + buckets: [ + { + count: 4634, + key: 'hello', + }, + ], + }, + }); + }); + it('should apply filters and queries', async () => { const { body } = await supertest .post('/api/lens/index_stats/logstash-2015.09.22/field') diff --git a/x-pack/test/api_integration/apis/metrics_ui/snapshot.ts b/x-pack/test/api_integration/apis/metrics_ui/snapshot.ts index bb0934b73a4c..7339c142fb02 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/snapshot.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/snapshot.ts @@ -67,7 +67,6 @@ export default function ({ getService }: FtrProviderContext) { 'value', '242fddb9d376bbf0e38025d81764847ee5ec0308adfa095918fd3266f9d06c6a' ); - expect(first(firstNode.path)).to.have.property('label', 'docker-autodiscovery_nginx_1'); expect(firstNode).to.have.property('metrics'); expect(firstNode.metrics).to.eql([ { @@ -136,7 +135,7 @@ export default function ({ getService }: FtrProviderContext) { expect(snapshot).to.have.property('nodes'); if (snapshot) { const { nodes } = snapshot; - expect(nodes.length).to.equal(136); + expect(nodes.length).to.equal(135); const firstNode = first(nodes) as any; expect(firstNode).to.have.property('path'); expect(firstNode.path.length).to.equal(1); @@ -295,7 +294,7 @@ export default function ({ getService }: FtrProviderContext) { expect(firstNode).to.have.property('metrics'); expect(firstNode.metrics).to.eql([ { - name: 'custom', + name: 'custom_0', value: 0.0016, max: 0.0018333333333333333, avg: 0.0013666666666666669, diff --git a/x-pack/test/api_integration/apis/ml/data_visualizer/get_field_stats.ts b/x-pack/test/api_integration/apis/ml/data_visualizer/get_field_stats.ts index 4ec8ae0429a6..5fe0dd5ee5e4 100644 --- a/x-pack/test/api_integration/apis/ml/data_visualizer/get_field_stats.ts +++ b/x-pack/test/api_integration/apis/ml/data_visualizer/get_field_stats.ts @@ -33,7 +33,7 @@ export default ({ getService }: FtrProviderContext) => { ], samplerShardSize: -1, // No sampling, as otherwise counts could vary on each run. timeFieldName: '@timestamp', - interval: '1d', + interval: 86400000, maxExamples: 10, }, expected: { @@ -41,7 +41,7 @@ export default ({ getService }: FtrProviderContext) => { responseBody: [ { documentCounts: { - interval: '1d', + interval: 86400000, buckets: { '1454803200000': 846, '1454889600000': 846, @@ -145,6 +145,7 @@ export default ({ getService }: FtrProviderContext) => { ], samplerShardSize: -1, // No sampling, as otherwise counts could vary on each run. timeFieldName: '@timestamp', + interval: 86400000, maxExamples: 10, }, expected: { diff --git a/x-pack/test/api_integration/apis/ml/jobs/jobs_exist.ts b/x-pack/test/api_integration/apis/ml/jobs/jobs_exist.ts new file mode 100644 index 000000000000..c48376b6a14f --- /dev/null +++ b/x-pack/test/api_integration/apis/ml/jobs/jobs_exist.ts @@ -0,0 +1,145 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../../ftr_provider_context'; +import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api'; +import { USER } from '../../../../functional/services/ml/security_common'; +import { SINGLE_METRIC_JOB_CONFIG, DATAFEED_CONFIG } from './common_jobs'; + +export default ({ getService }: FtrProviderContext) => { + const esArchiver = getService('esArchiver'); + const supertest = getService('supertestWithoutAuth'); + const ml = getService('ml'); + + const testSetupJobConfigs = [SINGLE_METRIC_JOB_CONFIG]; + + const responseBody = { + [SINGLE_METRIC_JOB_CONFIG.job_id]: true, + [`${SINGLE_METRIC_JOB_CONFIG.job_id.slice(0, 10)}*`]: true, // wildcard, use first 10 chars + [`${SINGLE_METRIC_JOB_CONFIG.job_id}_fail`]: false, + [`${SINGLE_METRIC_JOB_CONFIG.job_id.slice(0, 10)}_fail*`]: false, // wildcard, use first 10 chars + }; + + const testDataList = [ + { + testTitle: 'as ML Poweruser', + user: USER.ML_POWERUSER, + requestBody: { + jobIds: Object.keys(responseBody), + }, + expected: { + responseCode: 200, + responseBody, + }, + }, + { + testTitle: 'as ML Viewer', + user: USER.ML_VIEWER, + requestBody: { + jobIds: Object.keys(responseBody), + }, + expected: { + responseCode: 200, + responseBody, + }, + }, + ]; + + const testDataListUnauthorized = [ + { + testTitle: 'as ML Unauthorized user', + user: USER.ML_UNAUTHORIZED, + requestBody: { + jobIds: Object.keys(responseBody), + }, + expected: { + responseCode: 404, + error: 'Not Found', + }, + }, + ]; + + async function runJobsExistRequest( + user: USER, + requestBody: object, + expectedResponsecode: number + ): Promise { + const { body } = await supertest + .post('/api/ml/jobs/jobs_exist') + .auth(user, ml.securityCommon.getPasswordForUser(user)) + .set(COMMON_REQUEST_HEADERS) + .send(requestBody) + .expect(expectedResponsecode); + + return body; + } + + describe('jobs_exist', function () { + before(async () => { + await esArchiver.loadIfNeeded('ml/farequote'); + await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); + await ml.testResources.setKibanaTimeZoneToUTC(); + }); + + after(async () => { + await ml.api.cleanMlIndices(); + }); + + it('sets up jobs', async () => { + for (const job of testSetupJobConfigs) { + const datafeedId = `datafeed-${job.job_id}`; + await ml.api.createAnomalyDetectionJob(job); + await ml.api.openAnomalyDetectionJob(job.job_id); + await ml.api.createDatafeed({ + ...DATAFEED_CONFIG, + datafeed_id: datafeedId, + job_id: job.job_id, + }); + } + }); + + describe('jobs exist', function () { + for (const testData of testDataList) { + it(`${testData.testTitle}`, async () => { + const body = await runJobsExistRequest( + testData.user, + testData.requestBody, + testData.expected.responseCode + ); + const expectedResponse = testData.expected.responseBody; + const expectedRspJobIds = Object.keys(expectedResponse).sort((a, b) => + a.localeCompare(b) + ); + const actualRspJobIds = Object.keys(body).sort((a, b) => a.localeCompare(b)); + + expect(actualRspJobIds).to.have.length(expectedRspJobIds.length); + expect(actualRspJobIds).to.eql(expectedRspJobIds); + expectedRspJobIds.forEach((id) => { + expect(body[id]).to.eql(testData.expected.responseBody[id]); + }); + }); + } + }); + + describe('rejects request', function () { + for (const testData of testDataListUnauthorized) { + describe('fails to check jobs exist', function () { + it(`${testData.testTitle}`, async () => { + const body = await runJobsExistRequest( + testData.user, + testData.requestBody, + testData.expected.responseCode + ); + + expect(body).to.have.property('error').eql(testData.expected.error); + }); + }); + } + }); + }); +}; diff --git a/x-pack/test/api_integration/apis/security/basic_login.js b/x-pack/test/api_integration/apis/security/basic_login.js index 4b39b1bf32d5..43ef8e6b81ea 100644 --- a/x-pack/test/api_integration/apis/security/basic_login.js +++ b/x-pack/test/api_integration/apis/security/basic_login.js @@ -148,11 +148,8 @@ export default function ({ getService }) { ]); expect(apiResponse.body.username).to.be(validUsername); expect(apiResponse.body.authentication_provider).to.eql('__http__'); - expect(apiResponse.body.authentication_realm).to.eql({ - name: 'reserved', - type: 'reserved', - }); expect(apiResponse.body.authentication_type).to.be('realm'); + // Do not assert on the `authentication_realm`, as the value differes for on-prem vs cloud }); describe('with session cookie', () => { @@ -197,11 +194,8 @@ export default function ({ getService }) { ]); expect(apiResponse.body.username).to.be(validUsername); expect(apiResponse.body.authentication_provider).to.eql('basic'); - expect(apiResponse.body.authentication_realm).to.eql({ - name: 'reserved', - type: 'reserved', - }); expect(apiResponse.body.authentication_type).to.be('realm'); + // Do not assert on the `authentication_realm`, as the value differes for on-prem vs cloud }); it('should extend cookie on every successful non-system API call', async () => { diff --git a/x-pack/test/api_integration/apis/security_solution/ip_overview.ts b/x-pack/test/api_integration/apis/security_solution/network_details.ts similarity index 97% rename from x-pack/test/api_integration/apis/security_solution/ip_overview.ts rename to x-pack/test/api_integration/apis/security_solution/network_details.ts index 6493c0761799..cffcd790fa19 100644 --- a/x-pack/test/api_integration/apis/security_solution/ip_overview.ts +++ b/x-pack/test/api_integration/apis/security_solution/network_details.ts @@ -5,7 +5,7 @@ */ import expect from '@kbn/expect'; -import { ipOverviewQuery } from '../../../../plugins/security_solution/public/network/containers/ip_overview/index.gql_query'; +import { ipOverviewQuery } from '../../../../plugins/security_solution/public/network/containers/details/index.gql_query'; import { GetIpOverviewQuery } from '../../../../plugins/security_solution/public/graphql/types'; import { FtrProviderContext } from '../../ftr_provider_context'; diff --git a/x-pack/test/apm_api_integration/basic/tests/services/agent_name.ts b/x-pack/test/apm_api_integration/basic/tests/services/agent_name.ts index 5be5e43b359f..e4cceca573ce 100644 --- a/x-pack/test/apm_api_integration/basic/tests/services/agent_name.ts +++ b/x-pack/test/apm_api_integration/basic/tests/services/agent_name.ts @@ -6,14 +6,15 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; +import archives from '../../../common/archives_metadata'; export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const esArchiver = getService('esArchiver'); - // url parameters - const start = encodeURIComponent('2020-06-29T06:45:00.000Z'); - const end = encodeURIComponent('2020-06-29T06:49:00.000Z'); + const range = archives['apm_8.0.0']; + const start = encodeURIComponent(range.start); + const end = encodeURIComponent(range.end); describe('Agent name', () => { describe('when data is not loaded ', () => { @@ -28,8 +29,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); describe('when data is loaded', () => { - before(() => esArchiver.load('8.0.0')); - after(() => esArchiver.unload('8.0.0')); + before(() => esArchiver.load('apm_8.0.0')); + after(() => esArchiver.unload('apm_8.0.0')); it('returns the agent name', async () => { const response = await supertest.get( diff --git a/x-pack/test/apm_api_integration/common/archives_metadata.ts b/x-pack/test/apm_api_integration/common/archives_metadata.ts new file mode 100644 index 000000000000..38dde685dd3f --- /dev/null +++ b/x-pack/test/apm_api_integration/common/archives_metadata.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export default { + 'apm_8.0.0': { + start: '2020-09-10T08:07:13.274Z', + end: '2020-09-10T08:37:13.274Z', + }, +}; diff --git a/x-pack/test/apm_api_integration/common/config.ts b/x-pack/test/apm_api_integration/common/config.ts index 110f42115397..5edf1bf23e59 100644 --- a/x-pack/test/apm_api_integration/common/config.ts +++ b/x-pack/test/apm_api_integration/common/config.ts @@ -7,6 +7,7 @@ import { FtrConfigProviderContext } from '@kbn/test/types/ftr'; import supertestAsPromised from 'supertest-as-promised'; import { format, UrlObject } from 'url'; +import path from 'path'; import { InheritedFtrProviderContext, InheritedServices } from './ftr_provider_context'; import { PromiseReturnType } from '../../../plugins/apm/typings/common'; import { createApmUser, APM_TEST_PASSWORD, ApmUser } from './authentication'; @@ -49,6 +50,9 @@ export function createTestConfig(settings: Settings) { return { testFiles, servers, + esArchiver: { + directory: path.resolve(__dirname, './fixtures/es_archiver'), + }, services: { ...services, supertest: supertestAsApmReadUser, diff --git a/x-pack/test/apm_api_integration/basic/fixtures/es_archiver/8.0.0/data.json.gz b/x-pack/test/apm_api_integration/common/fixtures/es_archiver/8.0.0/data.json.gz similarity index 100% rename from x-pack/test/apm_api_integration/basic/fixtures/es_archiver/8.0.0/data.json.gz rename to x-pack/test/apm_api_integration/common/fixtures/es_archiver/8.0.0/data.json.gz diff --git a/x-pack/test/apm_api_integration/basic/fixtures/es_archiver/8.0.0/mappings.json b/x-pack/test/apm_api_integration/common/fixtures/es_archiver/8.0.0/mappings.json similarity index 100% rename from x-pack/test/apm_api_integration/basic/fixtures/es_archiver/8.0.0/mappings.json rename to x-pack/test/apm_api_integration/common/fixtures/es_archiver/8.0.0/mappings.json diff --git a/x-pack/test/apm_api_integration/common/fixtures/es_archiver/apm_8.0.0/data.json.gz b/x-pack/test/apm_api_integration/common/fixtures/es_archiver/apm_8.0.0/data.json.gz new file mode 100644 index 000000000000..34b673790ec0 Binary files /dev/null and b/x-pack/test/apm_api_integration/common/fixtures/es_archiver/apm_8.0.0/data.json.gz differ diff --git a/x-pack/test/apm_api_integration/common/fixtures/es_archiver/apm_8.0.0/mappings.json b/x-pack/test/apm_api_integration/common/fixtures/es_archiver/apm_8.0.0/mappings.json new file mode 100644 index 000000000000..5171ea03fb49 --- /dev/null +++ b/x-pack/test/apm_api_integration/common/fixtures/es_archiver/apm_8.0.0/mappings.json @@ -0,0 +1,63363 @@ +{ + "type": "index", + "value": { + "aliases": { + ".ml-anomalies-.write-android_homepage_high_latency_by_geo": { + "is_hidden": true + }, + ".ml-anomalies-.write-apm-environment_not_defined-7ed6-high_mean_transaction_duration": { + "is_hidden": true + }, + ".ml-anomalies-.write-apm-production-229a-high_mean_transaction_duration": { + "is_hidden": true + }, + ".ml-anomalies-.write-apm-testing-d457-high_mean_transaction_duration": { + "is_hidden": true + }, + ".ml-anomalies-.write-auto_http_0x73c4bc9426fb6908_high_latency_by_geo": { + "is_hidden": true + }, + ".ml-anomalies-.write-auto_http_0xa1e2426c5b01459d_high_latency_by_geo": { + "is_hidden": true + }, + ".ml-anomalies-.write-kibana-logs-ui-default-default-log-entry-categories-count": { + "is_hidden": true + }, + ".ml-anomalies-.write-kibana-logs-ui-default-default-log-entry-rate": { + "is_hidden": true + }, + ".ml-anomalies-android_homepage_high_latency_by_geo": { + "filter": { + "term": { + "job_id": { + "boost": 1, + "value": "android_homepage_high_latency_by_geo" + } + } + }, + "is_hidden": true + }, + ".ml-anomalies-apm-environment_not_defined-7ed6-high_mean_transaction_duration": { + "filter": { + "term": { + "job_id": { + "boost": 1, + "value": "apm-environment_not_defined-7ed6-high_mean_transaction_duration" + } + } + }, + "is_hidden": true + }, + ".ml-anomalies-apm-production-229a-high_mean_transaction_duration": { + "filter": { + "term": { + "job_id": { + "boost": 1, + "value": "apm-production-229a-high_mean_transaction_duration" + } + } + }, + "is_hidden": true + }, + ".ml-anomalies-apm-testing-d457-high_mean_transaction_duration": { + "filter": { + "term": { + "job_id": { + "boost": 1, + "value": "apm-testing-d457-high_mean_transaction_duration" + } + } + }, + "is_hidden": true + }, + ".ml-anomalies-auto_http_0x73c4bc9426fb6908_high_latency_by_geo": { + "filter": { + "term": { + "job_id": { + "boost": 1, + "value": "auto_http_0x73c4bc9426fb6908_high_latency_by_geo" + } + } + }, + "is_hidden": true + }, + ".ml-anomalies-auto_http_0xa1e2426c5b01459d_high_latency_by_geo": { + "filter": { + "term": { + "job_id": { + "boost": 1, + "value": "auto_http_0xa1e2426c5b01459d_high_latency_by_geo" + } + } + }, + "is_hidden": true + }, + ".ml-anomalies-kibana-logs-ui-default-default-log-entry-categories-count": { + "filter": { + "term": { + "job_id": { + "boost": 1, + "value": "kibana-logs-ui-default-default-log-entry-categories-count" + } + } + }, + "is_hidden": true + }, + ".ml-anomalies-kibana-logs-ui-default-default-log-entry-rate": { + "filter": { + "term": { + "job_id": { + "boost": 1, + "value": "kibana-logs-ui-default-default-log-entry-rate" + } + } + }, + "is_hidden": true + } + }, + "index": ".ml-anomalies-shared", + "mappings": { + "_meta": { + "version": "8.0.0" + }, + "dynamic_templates": [ + { + "strings_as_keywords": { + "mapping": { + "type": "keyword" + }, + "match": "*" + } + } + ], + "properties": { + "actual": { + "type": "double" + }, + "all_field_values": { + "analyzer": "whitespace", + "type": "text" + }, + "anomaly_score": { + "type": "double" + }, + "average_bucket_processing_time_ms": { + "type": "double" + }, + "bucket_allocation_failures_count": { + "type": "long" + }, + "bucket_count": { + "type": "long" + }, + "bucket_influencers": { + "properties": { + "anomaly_score": { + "type": "double" + }, + "bucket_span": { + "type": "long" + }, + "influencer_field_name": { + "type": "keyword" + }, + "initial_anomaly_score": { + "type": "double" + }, + "is_interim": { + "type": "boolean" + }, + "job_id": { + "type": "keyword" + }, + "probability": { + "type": "double" + }, + "raw_anomaly_score": { + "type": "double" + }, + "result_type": { + "type": "keyword" + }, + "timestamp": { + "type": "date" + } + }, + "type": "nested" + }, + "bucket_span": { + "type": "long" + }, + "by_field_name": { + "type": "keyword" + }, + "by_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "categorization_status": { + "type": "keyword" + }, + "categorized_doc_count": { + "type": "keyword" + }, + "category_id": { + "type": "long" + }, + "causes": { + "properties": { + "actual": { + "type": "double" + }, + "by_field_name": { + "type": "keyword" + }, + "by_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "correlated_by_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "field_name": { + "type": "keyword" + }, + "function": { + "type": "keyword" + }, + "function_description": { + "type": "keyword" + }, + "geo_results": { + "properties": { + "actual_point": { + "type": "geo_point" + }, + "typical_point": { + "type": "geo_point" + } + } + }, + "over_field_name": { + "type": "keyword" + }, + "over_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "partition_field_name": { + "type": "keyword" + }, + "partition_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "probability": { + "type": "double" + }, + "typical": { + "type": "double" + } + }, + "type": "nested" + }, + "dead_category_count": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "detector_index": { + "type": "integer" + }, + "earliest_record_timestamp": { + "type": "date" + }, + "empty_bucket_count": { + "type": "long" + }, + "event": { + "properties": { + "dataset": { + "type": "keyword" + } + } + }, + "event_count": { + "type": "long" + }, + "examples": { + "type": "text" + }, + "exponential_average_bucket_processing_time_ms": { + "type": "double" + }, + "exponential_average_calculation_context": { + "properties": { + "incremental_metric_value_ms": { + "type": "double" + }, + "latest_timestamp": { + "type": "date" + }, + "previous_exponential_average_ms": { + "type": "double" + } + } + }, + "failed_category_count": { + "type": "keyword" + }, + "field_name": { + "type": "keyword" + }, + "forecast_create_timestamp": { + "type": "date" + }, + "forecast_end_timestamp": { + "type": "date" + }, + "forecast_expiry_timestamp": { + "type": "date" + }, + "forecast_id": { + "type": "keyword" + }, + "forecast_lower": { + "type": "double" + }, + "forecast_memory_bytes": { + "type": "long" + }, + "forecast_messages": { + "type": "keyword" + }, + "forecast_prediction": { + "type": "double" + }, + "forecast_progress": { + "type": "double" + }, + "forecast_start_timestamp": { + "type": "date" + }, + "forecast_status": { + "type": "keyword" + }, + "forecast_upper": { + "type": "double" + }, + "frequent_category_count": { + "type": "keyword" + }, + "function": { + "type": "keyword" + }, + "function_description": { + "type": "keyword" + }, + "geo_results": { + "properties": { + "actual_point": { + "type": "geo_point" + }, + "typical_point": { + "type": "geo_point" + } + } + }, + "influencer_field_name": { + "type": "keyword" + }, + "influencer_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "influencer_score": { + "type": "double" + }, + "influencers": { + "properties": { + "influencer_field_name": { + "type": "keyword" + }, + "influencer_field_values": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + } + }, + "type": "nested" + }, + "initial_anomaly_score": { + "type": "double" + }, + "initial_influencer_score": { + "type": "double" + }, + "initial_record_score": { + "type": "double" + }, + "input_bytes": { + "type": "long" + }, + "input_field_count": { + "type": "long" + }, + "input_record_count": { + "type": "long" + }, + "invalid_date_count": { + "type": "long" + }, + "is_interim": { + "type": "boolean" + }, + "job_id": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "last_data_time": { + "type": "date" + }, + "latest_empty_bucket_timestamp": { + "type": "date" + }, + "latest_record_time_stamp": { + "type": "date" + }, + "latest_record_timestamp": { + "type": "date" + }, + "latest_result_time_stamp": { + "type": "date" + }, + "latest_sparse_bucket_timestamp": { + "type": "date" + }, + "log_time": { + "type": "date" + }, + "max_matching_length": { + "type": "long" + }, + "maximum_bucket_processing_time_ms": { + "type": "double" + }, + "memory_status": { + "type": "keyword" + }, + "min_version": { + "type": "keyword" + }, + "minimum_bucket_processing_time_ms": { + "type": "double" + }, + "missing_field_count": { + "type": "long" + }, + "mlcategory": { + "type": "keyword" + }, + "model_bytes": { + "type": "long" + }, + "model_bytes_exceeded": { + "type": "keyword" + }, + "model_bytes_memory_limit": { + "type": "keyword" + }, + "model_feature": { + "type": "keyword" + }, + "model_lower": { + "type": "double" + }, + "model_median": { + "type": "double" + }, + "model_size_stats": { + "properties": { + "bucket_allocation_failures_count": { + "type": "long" + }, + "categorization_status": { + "type": "keyword" + }, + "categorized_doc_count": { + "type": "keyword" + }, + "dead_category_count": { + "type": "keyword" + }, + "failed_category_count": { + "type": "keyword" + }, + "frequent_category_count": { + "type": "keyword" + }, + "job_id": { + "type": "keyword" + }, + "log_time": { + "type": "date" + }, + "memory_status": { + "type": "keyword" + }, + "model_bytes": { + "type": "long" + }, + "model_bytes_exceeded": { + "type": "keyword" + }, + "model_bytes_memory_limit": { + "type": "keyword" + }, + "peak_model_bytes": { + "type": "long" + }, + "rare_category_count": { + "type": "keyword" + }, + "result_type": { + "type": "keyword" + }, + "timestamp": { + "type": "date" + }, + "total_by_field_count": { + "type": "long" + }, + "total_category_count": { + "type": "keyword" + }, + "total_over_field_count": { + "type": "long" + }, + "total_partition_field_count": { + "type": "long" + } + } + }, + "model_upper": { + "type": "double" + }, + "monitor": { + "properties": { + "id": { + "type": "keyword" + }, + "name": { + "type": "keyword" + } + } + }, + "multi_bucket_impact": { + "type": "double" + }, + "num_matches": { + "type": "long" + }, + "observer": { + "properties": { + "geo": { + "properties": { + "name": { + "type": "keyword" + } + } + } + } + }, + "out_of_order_timestamp_count": { + "type": "long" + }, + "over_field_name": { + "type": "keyword" + }, + "over_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "partition_field_name": { + "type": "keyword" + }, + "partition_field_value": { + "copy_to": [ + "all_field_values" + ], + "type": "keyword" + }, + "peak_model_bytes": { + "type": "keyword" + }, + "preferred_to_categories": { + "type": "long" + }, + "probability": { + "type": "double" + }, + "processed_field_count": { + "type": "long" + }, + "processed_record_count": { + "type": "long" + }, + "processing_time_ms": { + "type": "long" + }, + "quantiles": { + "enabled": false, + "type": "object" + }, + "rare_category_count": { + "type": "keyword" + }, + "raw_anomaly_score": { + "type": "double" + }, + "record_score": { + "type": "double" + }, + "regex": { + "type": "keyword" + }, + "result_type": { + "type": "keyword" + }, + "retain": { + "type": "boolean" + }, + "scheduled_events": { + "type": "keyword" + }, + "search_count": { + "type": "long" + }, + "service": { + "properties": { + "name": { + "type": "keyword" + } + } + }, + "snapshot_doc_count": { + "type": "integer" + }, + "snapshot_id": { + "type": "keyword" + }, + "sparse_bucket_count": { + "type": "long" + }, + "terms": { + "type": "text" + }, + "timestamp": { + "type": "date" + }, + "total_by_field_count": { + "type": "long" + }, + "total_category_count": { + "type": "keyword" + }, + "total_over_field_count": { + "type": "long" + }, + "total_partition_field_count": { + "type": "long" + }, + "total_search_time_ms": { + "type": "double" + }, + "transaction": { + "properties": { + "type": { + "type": "keyword" + } + } + }, + "typical": { + "type": "double" + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "hidden": "true", + "number_of_replicas": "1", + "number_of_shards": "1", + "translog": { + "durability": "async" + } + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + }, + "index": ".ml-config", + "mappings": { + "_meta": { + "version": "8.0.0" + }, + "dynamic_templates": [ + { + "strings_as_keywords": { + "mapping": { + "type": "keyword" + }, + "match": "*" + } + } + ], + "properties": { + "aggregations": { + "enabled": false, + "type": "object" + }, + "allow_lazy_open": { + "type": "keyword" + }, + "analysis": { + "properties": { + "classification": { + "properties": { + "class_assignment_objective": { + "type": "keyword" + }, + "dependent_variable": { + "type": "keyword" + }, + "eta": { + "type": "double" + }, + "feature_bag_fraction": { + "type": "double" + }, + "gamma": { + "type": "double" + }, + "lambda": { + "type": "double" + }, + "max_trees": { + "type": "integer" + }, + "num_top_classes": { + "type": "integer" + }, + "num_top_feature_importance_values": { + "type": "integer" + }, + "prediction_field_name": { + "type": "keyword" + }, + "training_percent": { + "type": "double" + } + } + }, + "outlier_detection": { + "properties": { + "feature_influence_threshold": { + "type": "double" + }, + "method": { + "type": "keyword" + }, + "n_neighbors": { + "type": "integer" + } + } + }, + "regression": { + "properties": { + "dependent_variable": { + "type": "keyword" + }, + "eta": { + "type": "double" + }, + "feature_bag_fraction": { + "type": "double" + }, + "gamma": { + "type": "double" + }, + "lambda": { + "type": "double" + }, + "loss_function": { + "type": "keyword" + }, + "loss_function_parameter": { + "type": "double" + }, + "max_trees": { + "type": "integer" + }, + "num_top_feature_importance_values": { + "type": "integer" + }, + "prediction_field_name": { + "type": "keyword" + }, + "training_percent": { + "type": "double" + } + } + } + } + }, + "analysis_config": { + "properties": { + "bucket_span": { + "type": "keyword" + }, + "categorization_analyzer": { + "enabled": false, + "type": "object" + }, + "categorization_field_name": { + "type": "keyword" + }, + "categorization_filters": { + "type": "keyword" + }, + "detectors": { + "properties": { + "by_field_name": { + "type": "keyword" + }, + "custom_rules": { + "properties": { + "actions": { + "type": "keyword" + }, + "conditions": { + "properties": { + "applies_to": { + "type": "keyword" + }, + "operator": { + "type": "keyword" + }, + "value": { + "type": "double" + } + }, + "type": "nested" + }, + "scope": { + "enabled": false, + "type": "object" + } + }, + "type": "nested" + }, + "detector_description": { + "type": "text" + }, + "detector_index": { + "type": "integer" + }, + "exclude_frequent": { + "type": "keyword" + }, + "field_name": { + "type": "keyword" + }, + "function": { + "type": "keyword" + }, + "over_field_name": { + "type": "keyword" + }, + "partition_field_name": { + "type": "keyword" + }, + "use_null": { + "type": "boolean" + } + } + }, + "influencers": { + "type": "keyword" + }, + "latency": { + "type": "keyword" + }, + "multivariate_by_fields": { + "type": "boolean" + }, + "per_partition_categorization": { + "properties": { + "enabled": { + "type": "boolean" + }, + "stop_on_warn": { + "type": "boolean" + } + } + }, + "summary_count_field_name": { + "type": "keyword" + } + } + }, + "analysis_limits": { + "properties": { + "categorization_examples_limit": { + "type": "long" + }, + "model_memory_limit": { + "type": "keyword" + } + } + }, + "analyzed_fields": { + "enabled": false, + "type": "object" + }, + "background_persist_interval": { + "type": "keyword" + }, + "chunking_config": { + "properties": { + "mode": { + "type": "keyword" + }, + "time_span": { + "type": "keyword" + } + } + }, + "config_type": { + "type": "keyword" + }, + "create_time": { + "type": "date" + }, + "custom_settings": { + "enabled": false, + "type": "object" + }, + "daily_model_snapshot_retention_after_days": { + "type": "long" + }, + "data_description": { + "properties": { + "field_delimiter": { + "type": "keyword" + }, + "format": { + "type": "keyword" + }, + "quote_character": { + "type": "keyword" + }, + "time_field": { + "type": "keyword" + }, + "time_format": { + "type": "keyword" + } + } + }, + "datafeed_id": { + "type": "keyword" + }, + "delayed_data_check_config": { + "properties": { + "check_window": { + "type": "keyword" + }, + "enabled": { + "type": "boolean" + } + } + }, + "deleting": { + "type": "keyword" + }, + "description": { + "type": "text" + }, + "dest": { + "properties": { + "index": { + "type": "keyword" + }, + "results_field": { + "type": "keyword" + } + } + }, + "finished_time": { + "type": "date" + }, + "frequency": { + "type": "keyword" + }, + "groups": { + "type": "keyword" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "id": { + "type": "keyword" + }, + "indices": { + "type": "keyword" + }, + "indices_options": { + "enabled": false, + "type": "object" + }, + "job_id": { + "type": "keyword" + }, + "job_type": { + "type": "keyword" + }, + "job_version": { + "type": "keyword" + }, + "max_empty_searches": { + "type": "keyword" + }, + "max_num_threads": { + "type": "integer" + }, + "model_plot_config": { + "properties": { + "annotations_enabled": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "terms": { + "type": "keyword" + } + } + }, + "model_snapshot_id": { + "type": "keyword" + }, + "model_snapshot_min_version": { + "type": "keyword" + }, + "model_snapshot_retention_days": { + "type": "long" + }, + "query": { + "enabled": false, + "type": "object" + }, + "query_delay": { + "type": "keyword" + }, + "renormalization_window_days": { + "type": "long" + }, + "results_index_name": { + "type": "keyword" + }, + "results_retention_days": { + "type": "long" + }, + "script_fields": { + "enabled": false, + "type": "object" + }, + "scroll_size": { + "type": "long" + }, + "source": { + "properties": { + "_source": { + "enabled": false, + "type": "object" + }, + "index": { + "type": "keyword" + }, + "query": { + "enabled": false, + "type": "object" + } + } + }, + "version": { + "type": "keyword" + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "0-1", + "max_result_window": "10000", + "number_of_replicas": "1", + "number_of_shards": "1" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-error": { + "is_write_index": false + } + }, + "index": "apm-8.0.0-error-000001", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "company": { + "type": "keyword" + }, + "foo": { + "type": "keyword" + }, + "lorem": { + "type": "keyword" + }, + "multi-line": { + "type": "keyword" + }, + "this-is-a-very-long-tag-name-without-any-spaces": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "false", + "codec": "best_compression", + "lifecycle": { + "indexing_complete": "true", + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-error" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "0", + "number_of_shards": "1", + "priority": "50", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-error": { + "is_write_index": false + } + }, + "index": "apm-8.0.0-error-000002", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "company": { + "type": "keyword" + }, + "customer_tier": { + "type": "keyword" + }, + "foo": { + "type": "keyword" + }, + "lorem": { + "type": "keyword" + }, + "multi-line": { + "type": "keyword" + }, + "request_id": { + "type": "keyword" + }, + "this-is-a-very-long-tag-name-without-any-spaces": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "false", + "codec": "best_compression", + "lifecycle": { + "indexing_complete": "true", + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-error" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "0", + "number_of_shards": "1", + "priority": "50", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-error": { + "is_write_index": false + } + }, + "index": "apm-8.0.0-error-2020.07.31-000001", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels_string": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels_boolean": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels_*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "path": "agent.name", + "type": "alias" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "child": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "dynamic": "false", + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "company": { + "type": "keyword" + }, + "customer_tier": { + "type": "keyword" + }, + "foo": { + "type": "keyword" + }, + "lorem": { + "type": "keyword" + }, + "multi-line": { + "type": "keyword" + }, + "request_id": { + "type": "keyword" + }, + "this-is-a-very-long-tag-name-without-any-spaces": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "histogram": { + "type": "histogram" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "root": { + "type": "boolean" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "codec": "best_compression", + "lifecycle": { + "indexing_complete": "true", + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-error" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "1", + "number_of_shards": "1", + "priority": "100", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-error": { + "is_write_index": true + } + }, + "index": "apm-8.0.0-error-2020.07.31-000002", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels_string": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels_boolean": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels_*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "path": "agent.name", + "type": "alias" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "child": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "dynamic": "false", + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "company": { + "type": "keyword" + }, + "customer_tier": { + "type": "keyword" + }, + "request_id": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "histogram": { + "type": "histogram" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "root": { + "type": "boolean" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "codec": "best_compression", + "lifecycle": { + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-error" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "1", + "number_of_shards": "1", + "priority": "100", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-metric": { + "is_write_index": false + } + }, + "index": "apm-8.0.0-metric-000001", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "golang": { + "properties": { + "goroutines": { + "type": "long" + }, + "heap": { + "properties": { + "allocations": { + "properties": { + "active": { + "type": "float" + }, + "allocated": { + "type": "float" + }, + "frees": { + "type": "float" + }, + "idle": { + "type": "float" + }, + "mallocs": { + "type": "float" + }, + "objects": { + "type": "long" + }, + "total": { + "type": "float" + } + } + }, + "gc": { + "properties": { + "cpu_fraction": { + "type": "float" + }, + "next_gc_limit": { + "type": "float" + }, + "total_count": { + "type": "long" + }, + "total_pause": { + "properties": { + "ns": { + "type": "float" + } + } + } + } + }, + "system": { + "properties": { + "obtained": { + "type": "float" + }, + "released": { + "type": "float" + }, + "stack": { + "type": "long" + }, + "total": { + "type": "float" + } + } + } + } + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "jvm": { + "properties": { + "gc": { + "properties": { + "alloc": { + "type": "float" + }, + "count": { + "type": "long" + }, + "time": { + "type": "long" + } + } + }, + "memory": { + "properties": { + "heap": { + "properties": { + "committed": { + "type": "float" + }, + "max": { + "type": "float" + }, + "used": { + "type": "float" + } + } + }, + "non_heap": { + "properties": { + "committed": { + "type": "float" + }, + "max": { + "type": "long" + }, + "used": { + "type": "float" + } + } + } + } + }, + "thread": { + "properties": { + "count": { + "type": "long" + } + } + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "env": { + "type": "keyword" + }, + "hostname": { + "type": "keyword" + }, + "name": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "nodejs": { + "properties": { + "eventloop": { + "properties": { + "delay": { + "properties": { + "avg": { + "properties": { + "ms": { + "type": "float" + } + } + }, + "ns": { + "type": "long" + } + } + } + } + }, + "handles": { + "properties": { + "active": { + "type": "long" + } + } + }, + "memory": { + "properties": { + "heap": { + "properties": { + "allocated": { + "properties": { + "bytes": { + "type": "float" + } + } + }, + "used": { + "properties": { + "bytes": { + "type": "float" + } + } + } + } + } + } + }, + "requests": { + "properties": { + "active": { + "type": "long" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ruby": { + "properties": { + "gc": { + "properties": { + "count": { + "type": "long" + } + } + }, + "heap": { + "properties": { + "allocations": { + "properties": { + "total": { + "type": "float" + } + } + }, + "slots": { + "properties": { + "free": { + "type": "long" + }, + "live": { + "type": "long" + } + } + } + } + }, + "threads": { + "type": "long" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "system": { + "properties": { + "norm": { + "properties": { + "pct": { + "type": "float" + } + } + } + } + }, + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + }, + "user": { + "properties": { + "norm": { + "properties": { + "pct": { + "type": "float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "false", + "codec": "best_compression", + "lifecycle": { + "indexing_complete": "true", + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-metric" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "0", + "number_of_shards": "1", + "priority": "50", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-metric": { + "is_write_index": false + } + }, + "index": "apm-8.0.0-metric-000002", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "golang": { + "properties": { + "goroutines": { + "type": "long" + }, + "heap": { + "properties": { + "allocations": { + "properties": { + "active": { + "type": "float" + }, + "allocated": { + "type": "float" + }, + "frees": { + "type": "long" + }, + "idle": { + "type": "float" + }, + "mallocs": { + "type": "long" + }, + "objects": { + "type": "long" + }, + "total": { + "type": "float" + } + } + }, + "gc": { + "properties": { + "cpu_fraction": { + "type": "float" + }, + "next_gc_limit": { + "type": "float" + }, + "total_count": { + "type": "long" + }, + "total_pause": { + "properties": { + "ns": { + "type": "float" + } + } + } + } + }, + "system": { + "properties": { + "obtained": { + "type": "float" + }, + "released": { + "type": "float" + }, + "stack": { + "type": "long" + }, + "total": { + "type": "float" + } + } + } + } + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "jvm": { + "properties": { + "gc": { + "properties": { + "alloc": { + "type": "float" + }, + "count": { + "type": "long" + }, + "time": { + "type": "long" + } + } + }, + "memory": { + "properties": { + "heap": { + "properties": { + "committed": { + "type": "float" + }, + "max": { + "type": "float" + }, + "used": { + "type": "float" + } + } + }, + "non_heap": { + "properties": { + "committed": { + "type": "float" + }, + "max": { + "type": "long" + }, + "used": { + "type": "float" + } + } + } + } + }, + "thread": { + "properties": { + "count": { + "type": "long" + } + } + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "env": { + "type": "keyword" + }, + "hostname": { + "type": "keyword" + }, + "name": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "nodejs": { + "properties": { + "eventloop": { + "properties": { + "delay": { + "properties": { + "avg": { + "properties": { + "ms": { + "type": "float" + } + } + }, + "ns": { + "type": "long" + } + } + } + } + }, + "handles": { + "properties": { + "active": { + "type": "long" + } + } + }, + "memory": { + "properties": { + "arrayBuffers": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "external": { + "properties": { + "bytes": { + "type": "float" + } + } + }, + "heap": { + "properties": { + "allocated": { + "properties": { + "bytes": { + "type": "float" + } + } + }, + "used": { + "properties": { + "bytes": { + "type": "float" + } + } + } + } + } + } + }, + "requests": { + "properties": { + "active": { + "type": "long" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ruby": { + "properties": { + "gc": { + "properties": { + "count": { + "type": "long" + } + } + }, + "heap": { + "properties": { + "allocations": { + "properties": { + "total": { + "type": "float" + } + } + }, + "slots": { + "properties": { + "free": { + "type": "long" + }, + "live": { + "type": "long" + } + } + } + } + }, + "threads": { + "type": "long" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "system": { + "properties": { + "norm": { + "properties": { + "pct": { + "type": "float" + } + } + } + } + }, + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + }, + "user": { + "properties": { + "norm": { + "properties": { + "pct": { + "type": "float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "false", + "codec": "best_compression", + "lifecycle": { + "indexing_complete": "true", + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-metric" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "0", + "number_of_shards": "1", + "priority": "50", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-metric": { + "is_write_index": false + } + }, + "index": "apm-8.0.0-metric-2020.07.31-000001", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels_string": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels_boolean": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels_*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "path": "agent.name", + "type": "alias" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "child": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "dynamic": "false", + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "clr": { + "properties": { + "gc": { + "properties": { + "count": { + "type": "long" + }, + "gen0size": { + "type": "float" + }, + "gen1size": { + "type": "float" + }, + "gen2size": { + "type": "float" + }, + "gen3size": { + "type": "float" + } + } + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "golang": { + "properties": { + "goroutines": { + "type": "long" + }, + "heap": { + "properties": { + "allocations": { + "properties": { + "active": { + "type": "float" + }, + "allocated": { + "type": "float" + }, + "frees": { + "type": "long" + }, + "idle": { + "type": "float" + }, + "mallocs": { + "type": "long" + }, + "objects": { + "type": "long" + }, + "total": { + "type": "float" + } + } + }, + "gc": { + "properties": { + "cpu_fraction": { + "type": "float" + }, + "next_gc_limit": { + "type": "float" + }, + "total_count": { + "type": "long" + }, + "total_pause": { + "properties": { + "ns": { + "type": "long" + } + } + } + } + }, + "system": { + "properties": { + "obtained": { + "type": "float" + }, + "released": { + "type": "float" + }, + "stack": { + "type": "long" + }, + "total": { + "type": "float" + } + } + } + } + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "jvm": { + "properties": { + "gc": { + "properties": { + "alloc": { + "type": "float" + }, + "count": { + "type": "long" + }, + "time": { + "type": "long" + } + } + }, + "memory": { + "properties": { + "heap": { + "properties": { + "committed": { + "type": "float" + }, + "max": { + "type": "float" + }, + "pool": { + "properties": { + "committed": { + "type": "float" + }, + "max": { + "type": "float" + }, + "used": { + "type": "long" + } + } + }, + "used": { + "type": "float" + } + } + }, + "non_heap": { + "properties": { + "committed": { + "type": "float" + }, + "max": { + "type": "long" + }, + "used": { + "type": "float" + } + } + } + } + }, + "thread": { + "properties": { + "count": { + "type": "long" + } + } + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "env": { + "type": "keyword" + }, + "hostname": { + "type": "keyword" + }, + "name": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "nodejs": { + "properties": { + "eventloop": { + "properties": { + "delay": { + "properties": { + "avg": { + "properties": { + "ms": { + "type": "float" + } + } + }, + "ns": { + "type": "long" + } + } + } + } + }, + "handles": { + "properties": { + "active": { + "type": "long" + } + } + }, + "memory": { + "properties": { + "arrayBuffers": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "external": { + "properties": { + "bytes": { + "type": "float" + } + } + }, + "heap": { + "properties": { + "allocated": { + "properties": { + "bytes": { + "type": "float" + } + } + }, + "used": { + "properties": { + "bytes": { + "type": "float" + } + } + } + } + } + } + }, + "requests": { + "properties": { + "active": { + "type": "long" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ruby": { + "properties": { + "gc": { + "properties": { + "count": { + "type": "long" + } + } + }, + "heap": { + "properties": { + "allocations": { + "properties": { + "total": { + "type": "long" + } + } + }, + "slots": { + "properties": { + "free": { + "type": "long" + }, + "live": { + "type": "long" + } + } + } + } + }, + "threads": { + "type": "long" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cgroup": { + "properties": { + "memory": { + "properties": { + "mem": { + "properties": { + "limit": { + "properties": { + "bytes": { + "type": "float" + } + } + }, + "usage": { + "properties": { + "bytes": { + "type": "float" + } + } + } + } + }, + "stats": { + "properties": { + "inactive_file": { + "properties": { + "bytes": { + "type": "float" + } + } + } + } + } + } + } + } + }, + "cpu": { + "properties": { + "system": { + "properties": { + "norm": { + "properties": { + "pct": { + "type": "float" + } + } + } + } + }, + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + }, + "user": { + "properties": { + "norm": { + "properties": { + "pct": { + "type": "float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "histogram": { + "type": "histogram" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "root": { + "type": "boolean" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "codec": "best_compression", + "lifecycle": { + "indexing_complete": "true", + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-metric" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "1", + "number_of_shards": "1", + "priority": "100", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-metric": { + "is_write_index": true + } + }, + "index": "apm-8.0.0-metric-2020.07.31-000002", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels_string": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels_boolean": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels_*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "path": "agent.name", + "type": "alias" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "child": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "dynamic": "false", + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "clr": { + "properties": { + "gc": { + "properties": { + "count": { + "type": "long" + }, + "gen0size": { + "type": "float" + }, + "gen1size": { + "type": "float" + }, + "gen2size": { + "type": "float" + }, + "gen3size": { + "type": "float" + } + } + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "golang": { + "properties": { + "goroutines": { + "type": "long" + }, + "heap": { + "properties": { + "allocations": { + "properties": { + "active": { + "type": "float" + }, + "allocated": { + "type": "float" + }, + "frees": { + "type": "float" + }, + "idle": { + "type": "float" + }, + "mallocs": { + "type": "float" + }, + "objects": { + "type": "long" + }, + "total": { + "type": "float" + } + } + }, + "gc": { + "properties": { + "cpu_fraction": { + "type": "float" + }, + "next_gc_limit": { + "type": "float" + }, + "total_count": { + "type": "long" + }, + "total_pause": { + "properties": { + "ns": { + "type": "float" + } + } + } + } + }, + "system": { + "properties": { + "obtained": { + "type": "float" + }, + "released": { + "type": "float" + }, + "stack": { + "type": "long" + }, + "total": { + "type": "float" + } + } + } + } + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "jvm": { + "properties": { + "gc": { + "properties": { + "alloc": { + "type": "float" + }, + "count": { + "type": "long" + }, + "time": { + "type": "long" + } + } + }, + "memory": { + "properties": { + "heap": { + "properties": { + "committed": { + "type": "float" + }, + "max": { + "type": "float" + }, + "pool": { + "properties": { + "committed": { + "type": "float" + }, + "max": { + "type": "float" + }, + "used": { + "type": "float" + } + } + }, + "used": { + "type": "float" + } + } + }, + "non_heap": { + "properties": { + "committed": { + "type": "float" + }, + "max": { + "type": "long" + }, + "used": { + "type": "float" + } + } + } + } + }, + "thread": { + "properties": { + "count": { + "type": "long" + } + } + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "env": { + "type": "keyword" + }, + "hostname": { + "type": "keyword" + }, + "name": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "nodejs": { + "properties": { + "eventloop": { + "properties": { + "delay": { + "properties": { + "avg": { + "properties": { + "ms": { + "type": "float" + } + } + }, + "ns": { + "type": "long" + } + } + } + } + }, + "handles": { + "properties": { + "active": { + "type": "long" + } + } + }, + "memory": { + "properties": { + "arrayBuffers": { + "properties": { + "bytes": { + "type": "float" + } + } + }, + "external": { + "properties": { + "bytes": { + "type": "float" + } + } + }, + "heap": { + "properties": { + "allocated": { + "properties": { + "bytes": { + "type": "float" + } + } + }, + "used": { + "properties": { + "bytes": { + "type": "float" + } + } + } + } + } + } + }, + "requests": { + "properties": { + "active": { + "type": "long" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ruby": { + "properties": { + "gc": { + "properties": { + "count": { + "type": "long" + } + } + }, + "heap": { + "properties": { + "allocations": { + "properties": { + "total": { + "type": "float" + } + } + }, + "slots": { + "properties": { + "free": { + "type": "long" + }, + "live": { + "type": "long" + } + } + } + } + }, + "threads": { + "type": "long" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cgroup": { + "properties": { + "memory": { + "properties": { + "mem": { + "properties": { + "limit": { + "properties": { + "bytes": { + "type": "float" + } + } + }, + "usage": { + "properties": { + "bytes": { + "type": "float" + } + } + } + } + }, + "stats": { + "properties": { + "inactive_file": { + "properties": { + "bytes": { + "type": "float" + } + } + } + } + } + } + } + } + }, + "cpu": { + "properties": { + "system": { + "properties": { + "norm": { + "properties": { + "pct": { + "type": "float" + } + } + } + } + }, + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + }, + "user": { + "properties": { + "norm": { + "properties": { + "pct": { + "type": "float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "histogram": { + "type": "histogram" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "root": { + "type": "boolean" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "codec": "best_compression", + "lifecycle": { + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-metric" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "1", + "number_of_shards": "1", + "priority": "100", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-span": { + "is_write_index": false + } + }, + "index": "apm-8.0.0-span-000001", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "foo": { + "type": "keyword" + }, + "productId": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "false", + "codec": "best_compression", + "lifecycle": { + "indexing_complete": "true", + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-span" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "0", + "number_of_shards": "1", + "priority": "50", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-span": { + "is_write_index": false + } + }, + "index": "apm-8.0.0-span-000002", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "foo": { + "type": "keyword" + }, + "productId": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "false", + "codec": "best_compression", + "lifecycle": { + "indexing_complete": "true", + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-span" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "0", + "number_of_shards": "1", + "priority": "50", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-span": { + "is_write_index": false + } + }, + "index": "apm-8.0.0-span-2020.07.31-000001", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels_string": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels_boolean": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels_*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "path": "agent.name", + "type": "alias" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "child": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "dynamic": "false", + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "foo": { + "type": "keyword" + }, + "productId": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "histogram": { + "type": "histogram" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "root": { + "type": "boolean" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "codec": "best_compression", + "lifecycle": { + "indexing_complete": "true", + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-span" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "1", + "number_of_shards": "1", + "priority": "100", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-span": { + "is_write_index": true + } + }, + "index": "apm-8.0.0-span-2020.07.31-000002", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels_string": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels_boolean": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels_*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "path": "agent.name", + "type": "alias" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "child": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "dynamic": "false", + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "foo": { + "type": "keyword" + }, + "productId": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "histogram": { + "type": "histogram" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "root": { + "type": "boolean" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "codec": "best_compression", + "lifecycle": { + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-span" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "1", + "number_of_shards": "1", + "priority": "100", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-transaction": { + "is_write_index": false + } + }, + "index": "apm-8.0.0-transaction-000001", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "company": { + "type": "keyword" + }, + "customer_email": { + "type": "keyword" + }, + "customer_name": { + "type": "keyword" + }, + "foo": { + "type": "keyword" + }, + "lorem": { + "type": "keyword" + }, + "multi-line": { + "type": "keyword" + }, + "served_from_cache": { + "type": "keyword" + }, + "this-is-a-very-long-tag-name-without-any-spaces": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + }, + "agent": { + "properties": { + "domComplete": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domInteractive": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "firstContentfulPaint": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "largestContentfulPaint": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "timeToFirstByte": { + "scaling_factor": 1000000, + "type": "scaled_float" + } + } + }, + "navigationTiming": { + "properties": { + "connectEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "connectStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domComplete": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domContentLoadedEventEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domContentLoadedEventStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domInteractive": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domLoading": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domainLookupEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domainLookupStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "fetchStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "loadEventEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "loadEventStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "requestStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "responseEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "responseStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "false", + "codec": "best_compression", + "lifecycle": { + "indexing_complete": "true", + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-transaction" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "0", + "number_of_shards": "1", + "priority": "50", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-transaction": { + "is_write_index": false + } + }, + "index": "apm-8.0.0-transaction-000002", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "company": { + "type": "keyword" + }, + "customer_email": { + "type": "keyword" + }, + "customer_name": { + "type": "keyword" + }, + "customer_tier": { + "type": "keyword" + }, + "foo": { + "type": "keyword" + }, + "lorem": { + "type": "keyword" + }, + "multi-line": { + "type": "keyword" + }, + "request_id": { + "type": "keyword" + }, + "served_from_cache": { + "type": "keyword" + }, + "this-is-a-very-long-tag-name-without-any-spaces": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + }, + "agent": { + "properties": { + "domComplete": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domInteractive": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "firstContentfulPaint": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "largestContentfulPaint": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "timeToFirstByte": { + "scaling_factor": 1000000, + "type": "scaled_float" + } + } + }, + "navigationTiming": { + "properties": { + "connectEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "connectStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domComplete": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domContentLoadedEventEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domContentLoadedEventStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domInteractive": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domLoading": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domainLookupEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domainLookupStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "fetchStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "loadEventEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "loadEventStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "requestStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "responseEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "responseStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "auto_expand_replicas": "false", + "codec": "best_compression", + "lifecycle": { + "indexing_complete": "true", + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-transaction" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "0", + "number_of_shards": "1", + "priority": "50", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-transaction": { + "is_write_index": false + } + }, + "index": "apm-8.0.0-transaction-2020.07.31-000001", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels_string": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels_boolean": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels_*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "path": "agent.name", + "type": "alias" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "child": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "dynamic": "false", + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "company": { + "type": "keyword" + }, + "customer_email": { + "type": "keyword" + }, + "customer_name": { + "type": "keyword" + }, + "customer_tier": { + "type": "keyword" + }, + "foo": { + "type": "keyword" + }, + "lorem": { + "type": "keyword" + }, + "multi-line": { + "type": "keyword" + }, + "request_id": { + "type": "keyword" + }, + "served_from_cache": { + "type": "keyword" + }, + "this-is-a-very-long-tag-name-without-any-spaces": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "histogram": { + "type": "histogram" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + }, + "agent": { + "properties": { + "domComplete": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domInteractive": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "timeToFirstByte": { + "scaling_factor": 1000000, + "type": "scaled_float" + } + } + }, + "navigationTiming": { + "properties": { + "connectEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "connectStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domComplete": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domContentLoadedEventEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domContentLoadedEventStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domInteractive": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domLoading": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domainLookupEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domainLookupStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "fetchStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "loadEventEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "loadEventStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "requestStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "responseEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "responseStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "root": { + "type": "boolean" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "codec": "best_compression", + "lifecycle": { + "indexing_complete": "true", + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-transaction" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "1", + "number_of_shards": "1", + "priority": "100", + "refresh_interval": "5s" + } + } + } +} + +{ + "type": "index", + "value": { + "aliases": { + "apm-8.0.0-transaction": { + "is_write_index": true + } + }, + "index": "apm-8.0.0-transaction-2020.07.31-000002", + "mappings": { + "_meta": { + "beat": "apm", + "version": "8.0.0" + }, + "date_detection": false, + "dynamic_templates": [ + { + "labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "container.labels.*" + } + }, + { + "dns.answers": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "dns.answers.*" + } + }, + { + "log.syslog": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "log.syslog.*" + } + }, + { + "network.inner": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "network.inner.*" + } + }, + { + "observer.egress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.egress.*" + } + }, + { + "observer.ingress": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "observer.ingress.*" + } + }, + { + "fields": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "fields.*" + } + }, + { + "docker.container.labels": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "docker.container.labels.*" + } + }, + { + "kubernetes.labels.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.labels.*" + } + }, + { + "kubernetes.annotations.*": { + "mapping": { + "type": "keyword" + }, + "path_match": "kubernetes.annotations.*" + } + }, + { + "labels_string": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "labels.*" + } + }, + { + "labels_boolean": { + "mapping": { + "type": "boolean" + }, + "match_mapping_type": "boolean", + "path_match": "labels.*" + } + }, + { + "labels_*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "labels.*" + } + }, + { + "transaction.marks": { + "mapping": { + "type": "keyword" + }, + "match_mapping_type": "string", + "path_match": "transaction.marks.*" + } + }, + { + "transaction.marks.*.*": { + "mapping": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "path_match": "transaction.marks.*.*" + } + }, + { + "strings_as_keyword": { + "mapping": { + "ignore_above": 1024, + "type": "keyword" + }, + "match_mapping_type": "string" + } + } + ], + "properties": { + "@timestamp": { + "type": "date" + }, + "agent": { + "dynamic": "false", + "properties": { + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "hostname": { + "path": "agent.name", + "type": "alias" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "child": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "client": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "cloud": { + "properties": { + "account": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "availability_zone": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "instance": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "machine": { + "dynamic": "false", + "properties": { + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "project": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "region": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "container": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "image": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "tag": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "type": "object" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "runtime": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "destination": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dll": { + "properties": { + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "dns": { + "properties": { + "answers": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "data": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "ttl": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "header_flags": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "op_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "question": { + "properties": { + "class": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "subdomain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "resolved_ip": { + "type": "ip" + }, + "response_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "docker": { + "properties": { + "container": { + "properties": { + "labels": { + "type": "object" + } + } + } + } + }, + "ecs": { + "properties": { + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "error": { + "dynamic": "false", + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "culprit": { + "ignore_above": 1024, + "type": "keyword" + }, + "exception": { + "properties": { + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "handled": { + "type": "boolean" + }, + "message": { + "norms": false, + "type": "text" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "grouping_key": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "norms": false, + "type": "text" + }, + "param_message": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "stack_trace": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "event": { + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "code": { + "ignore_above": 1024, + "type": "keyword" + }, + "created": { + "type": "date" + }, + "dataset": { + "ignore_above": 1024, + "type": "keyword" + }, + "duration": { + "type": "long" + }, + "end": { + "type": "date" + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingested": { + "type": "date" + }, + "kind": { + "ignore_above": 1024, + "type": "keyword" + }, + "module": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "outcome": { + "ignore_above": 1024, + "type": "keyword" + }, + "provider": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "risk_score": { + "type": "float" + }, + "risk_score_norm": { + "type": "float" + }, + "sequence": { + "type": "long" + }, + "severity": { + "type": "long" + }, + "start": { + "type": "date" + }, + "timezone": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "url": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "experimental": { + "dynamic": "true", + "type": "object" + }, + "fields": { + "type": "object" + }, + "file": { + "properties": { + "accessed": { + "type": "date" + }, + "attributes": { + "ignore_above": 1024, + "type": "keyword" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "created": { + "type": "date" + }, + "ctime": { + "type": "date" + }, + "device": { + "ignore_above": 1024, + "type": "keyword" + }, + "directory": { + "ignore_above": 1024, + "type": "keyword" + }, + "drive_letter": { + "ignore_above": 1, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "gid": { + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "inode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mime_type": { + "ignore_above": 1024, + "type": "keyword" + }, + "mode": { + "ignore_above": 1024, + "type": "keyword" + }, + "mtime": { + "type": "date" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "owner": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "size": { + "type": "long" + }, + "target_path": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "host": { + "dynamic": "false", + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "containerized": { + "type": "boolean" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "build": { + "ignore_above": 1024, + "type": "keyword" + }, + "codename": { + "ignore_above": 1024, + "type": "keyword" + }, + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "http": { + "dynamic": "false", + "properties": { + "request": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "method": { + "ignore_above": 1024, + "type": "keyword" + }, + "referrer": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "response": { + "properties": { + "body": { + "properties": { + "bytes": { + "type": "long" + }, + "content": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "bytes": { + "type": "long" + }, + "finished": { + "type": "boolean" + }, + "headers": { + "enabled": false, + "type": "object" + }, + "status_code": { + "type": "long" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "kubernetes": { + "dynamic": "false", + "properties": { + "annotations": { + "properties": { + "*": { + "type": "object" + } + } + }, + "container": { + "properties": { + "image": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "deployment": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "labels": { + "properties": { + "*": { + "type": "object" + } + } + }, + "namespace": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pod": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "uid": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "replicaset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "statefulset": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "labels": { + "dynamic": "true", + "properties": { + "company": { + "type": "keyword" + }, + "customer_email": { + "type": "keyword" + }, + "customer_name": { + "type": "keyword" + }, + "customer_tier": { + "type": "keyword" + }, + "foo": { + "type": "keyword" + }, + "lorem": { + "type": "keyword" + }, + "multi-line": { + "type": "keyword" + }, + "request_id": { + "type": "keyword" + }, + "served_from_cache": { + "type": "keyword" + }, + "this-is-a-very-long-tag-name-without-any-spaces": { + "type": "keyword" + } + } + }, + "log": { + "properties": { + "level": { + "ignore_above": 1024, + "type": "keyword" + }, + "logger": { + "ignore_above": 1024, + "type": "keyword" + }, + "origin": { + "properties": { + "file": { + "properties": { + "line": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "original": { + "ignore_above": 1024, + "type": "keyword" + }, + "syslog": { + "properties": { + "facility": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "priority": { + "type": "long" + }, + "severity": { + "properties": { + "code": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + } + } + }, + "message": { + "norms": false, + "type": "text" + }, + "network": { + "properties": { + "application": { + "ignore_above": 1024, + "type": "keyword" + }, + "bytes": { + "type": "long" + }, + "community_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "direction": { + "ignore_above": 1024, + "type": "keyword" + }, + "forwarded_ip": { + "type": "ip" + }, + "iana_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "inner": { + "properties": { + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "packets": { + "type": "long" + }, + "protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "transport": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "observer": { + "dynamic": "false", + "properties": { + "egress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hostname": { + "ignore_above": 1024, + "type": "keyword" + }, + "ingress": { + "properties": { + "interface": { + "properties": { + "alias": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "zone": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "listening": { + "ignore_above": 1024, + "type": "keyword" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + }, + "serial_number": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "vendor": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_major": { + "type": "byte" + } + } + }, + "organization": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "package": { + "properties": { + "architecture": { + "ignore_above": 1024, + "type": "keyword" + }, + "build_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "checksum": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "install_scope": { + "ignore_above": 1024, + "type": "keyword" + }, + "installed": { + "type": "date" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "size": { + "type": "long" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "parent": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "process": { + "dynamic": "false", + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "parent": { + "properties": { + "args": { + "ignore_above": 1024, + "type": "keyword" + }, + "args_count": { + "type": "long" + }, + "code_signature": { + "properties": { + "exists": { + "type": "boolean" + }, + "status": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "trusted": { + "type": "boolean" + }, + "valid": { + "type": "boolean" + } + } + }, + "command_line": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "entity_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "executable": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "exit_code": { + "type": "long" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha512": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pe": { + "properties": { + "company": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "file_version": { + "ignore_above": 1024, + "type": "keyword" + }, + "original_file_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "product": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "pgid": { + "type": "long" + }, + "pid": { + "type": "long" + }, + "ppid": { + "type": "long" + }, + "start": { + "type": "date" + }, + "thread": { + "properties": { + "id": { + "type": "long" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "title": { + "ignore_above": 1024, + "type": "keyword" + }, + "uptime": { + "type": "long" + }, + "working_directory": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "processor": { + "properties": { + "event": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "profile": { + "dynamic": "false", + "properties": { + "alloc_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "alloc_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "cpu": { + "properties": { + "ns": { + "type": "long" + } + } + }, + "duration": { + "type": "long" + }, + "inuse_objects": { + "properties": { + "count": { + "type": "long" + } + } + }, + "inuse_space": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "samples": { + "properties": { + "count": { + "type": "long" + } + } + }, + "stack": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + }, + "top": { + "dynamic": "false", + "properties": { + "filename": { + "ignore_above": 1024, + "type": "keyword" + }, + "function": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "line": { + "type": "long" + } + } + } + } + }, + "registry": { + "properties": { + "data": { + "properties": { + "bytes": { + "ignore_above": 1024, + "type": "keyword" + }, + "strings": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hive": { + "ignore_above": 1024, + "type": "keyword" + }, + "key": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "value": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "related": { + "properties": { + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "ip": { + "type": "ip" + }, + "user": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "rule": { + "properties": { + "author": { + "ignore_above": 1024, + "type": "keyword" + }, + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "license": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "ruleset": { + "ignore_above": 1024, + "type": "keyword" + }, + "uuid": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "server": { + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "service": { + "dynamic": "false", + "properties": { + "environment": { + "ignore_above": 1024, + "type": "keyword" + }, + "ephemeral_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "framework": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "language": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "node": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "runtime": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "state": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "source": { + "dynamic": "false", + "properties": { + "address": { + "ignore_above": 1024, + "type": "keyword" + }, + "as": { + "properties": { + "number": { + "type": "long" + }, + "organization": { + "properties": { + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "bytes": { + "type": "long" + }, + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "geo": { + "properties": { + "city_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "continent_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "country_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "location": { + "type": "geo_point" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_iso_code": { + "ignore_above": 1024, + "type": "keyword" + }, + "region_name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "ip": { + "type": "ip" + }, + "mac": { + "ignore_above": 1024, + "type": "keyword" + }, + "nat": { + "properties": { + "ip": { + "type": "ip" + }, + "port": { + "type": "long" + } + } + }, + "packets": { + "type": "long" + }, + "port": { + "type": "long" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "user": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "sourcemap": { + "dynamic": "false", + "properties": { + "bundle_filepath": { + "ignore_above": 1024, + "type": "keyword" + }, + "service": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "span": { + "dynamic": "false", + "properties": { + "action": { + "ignore_above": 1024, + "type": "keyword" + }, + "db": { + "dynamic": "false", + "properties": { + "link": { + "ignore_above": 1024, + "type": "keyword" + }, + "rows_affected": { + "type": "long" + } + } + }, + "destination": { + "dynamic": "false", + "properties": { + "service": { + "dynamic": "false", + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "resource": { + "ignore_above": 1024, + "type": "keyword" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "duration": { + "properties": { + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "start": { + "properties": { + "us": { + "type": "long" + } + } + }, + "subtype": { + "ignore_above": 1024, + "type": "keyword" + }, + "sync": { + "type": "boolean" + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "system": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "actual": { + "properties": { + "free": { + "type": "long" + } + } + }, + "total": { + "type": "long" + } + } + }, + "process": { + "properties": { + "cpu": { + "properties": { + "total": { + "properties": { + "norm": { + "properties": { + "pct": { + "scaling_factor": 1000, + "type": "scaled_float" + } + } + } + } + } + } + }, + "memory": { + "properties": { + "rss": { + "properties": { + "bytes": { + "type": "long" + } + } + }, + "size": { + "type": "long" + } + } + } + } + } + } + }, + "tags": { + "ignore_above": 1024, + "type": "keyword" + }, + "threat": { + "properties": { + "framework": { + "ignore_above": 1024, + "type": "keyword" + }, + "tactic": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "technique": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "timeseries": { + "properties": { + "instance": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "timestamp": { + "properties": { + "us": { + "type": "long" + } + } + }, + "tls": { + "properties": { + "cipher": { + "ignore_above": 1024, + "type": "keyword" + }, + "client": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "server_name": { + "ignore_above": 1024, + "type": "keyword" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + }, + "supported_ciphers": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "curve": { + "ignore_above": 1024, + "type": "keyword" + }, + "established": { + "type": "boolean" + }, + "next_protocol": { + "ignore_above": 1024, + "type": "keyword" + }, + "resumed": { + "type": "boolean" + }, + "server": { + "properties": { + "certificate": { + "ignore_above": 1024, + "type": "keyword" + }, + "certificate_chain": { + "ignore_above": 1024, + "type": "keyword" + }, + "hash": { + "properties": { + "md5": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha1": { + "ignore_above": 1024, + "type": "keyword" + }, + "sha256": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "issuer": { + "ignore_above": 1024, + "type": "keyword" + }, + "ja3s": { + "ignore_above": 1024, + "type": "keyword" + }, + "not_after": { + "type": "date" + }, + "not_before": { + "type": "date" + }, + "subject": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + }, + "version_protocol": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "trace": { + "dynamic": "false", + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "tracing": { + "properties": { + "trace": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "transaction": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "transaction": { + "dynamic": "false", + "properties": { + "breakdown": { + "properties": { + "count": { + "type": "long" + } + } + }, + "duration": { + "properties": { + "count": { + "type": "long" + }, + "histogram": { + "type": "histogram" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + }, + "us": { + "type": "long" + } + } + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "marks": { + "dynamic": "true", + "properties": { + "*": { + "properties": { + "*": { + "dynamic": "true", + "type": "object" + } + } + }, + "agent": { + "properties": { + "domComplete": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domInteractive": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "firstContentfulPaint": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "largestContentfulPaint": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "timeToFirstByte": { + "scaling_factor": 1000000, + "type": "scaled_float" + } + } + }, + "navigationTiming": { + "properties": { + "connectEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "connectStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domComplete": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domContentLoadedEventEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domContentLoadedEventStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domInteractive": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domLoading": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domainLookupEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "domainLookupStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "fetchStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "loadEventEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "loadEventStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "requestStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "responseEnd": { + "scaling_factor": 1000000, + "type": "scaled_float" + }, + "responseStart": { + "scaling_factor": 1000000, + "type": "scaled_float" + } + } + } + } + }, + "message": { + "dynamic": "false", + "properties": { + "age": { + "properties": { + "ms": { + "type": "long" + } + } + }, + "queue": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "result": { + "ignore_above": 1024, + "type": "keyword" + }, + "root": { + "type": "boolean" + }, + "sampled": { + "type": "boolean" + }, + "self_time": { + "properties": { + "count": { + "type": "long" + }, + "sum": { + "properties": { + "us": { + "type": "long" + } + } + } + } + }, + "span_count": { + "properties": { + "dropped": { + "type": "long" + } + } + }, + "type": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "url": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "extension": { + "ignore_above": 1024, + "type": "keyword" + }, + "fragment": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "password": { + "ignore_above": 1024, + "type": "keyword" + }, + "path": { + "ignore_above": 1024, + "type": "keyword" + }, + "port": { + "type": "long" + }, + "query": { + "ignore_above": 1024, + "type": "keyword" + }, + "registered_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "scheme": { + "ignore_above": 1024, + "type": "keyword" + }, + "top_level_domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "username": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user": { + "dynamic": "false", + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "email": { + "ignore_above": 1024, + "type": "keyword" + }, + "full_name": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "group": { + "properties": { + "domain": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "hash": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "user_agent": { + "dynamic": "false", + "properties": { + "device": { + "properties": { + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "original": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "os": { + "properties": { + "family": { + "ignore_above": 1024, + "type": "keyword" + }, + "full": { + "ignore_above": 1024, + "type": "keyword" + }, + "kernel": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + }, + "platform": { + "ignore_above": 1024, + "type": "keyword" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "view spans": { + "ignore_above": 1024, + "type": "keyword" + }, + "vlan": { + "properties": { + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "name": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "vulnerability": { + "properties": { + "category": { + "ignore_above": 1024, + "type": "keyword" + }, + "classification": { + "ignore_above": 1024, + "type": "keyword" + }, + "description": { + "fields": { + "text": { + "norms": false, + "type": "text" + } + }, + "ignore_above": 1024, + "type": "keyword" + }, + "enumeration": { + "ignore_above": 1024, + "type": "keyword" + }, + "id": { + "ignore_above": 1024, + "type": "keyword" + }, + "reference": { + "ignore_above": 1024, + "type": "keyword" + }, + "report_id": { + "ignore_above": 1024, + "type": "keyword" + }, + "scanner": { + "properties": { + "vendor": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "score": { + "properties": { + "base": { + "type": "float" + }, + "environmental": { + "type": "float" + }, + "temporal": { + "type": "float" + }, + "version": { + "ignore_above": 1024, + "type": "keyword" + } + } + }, + "severity": { + "ignore_above": 1024, + "type": "keyword" + } + } + } + } + }, + "settings": { + "index": { + "codec": "best_compression", + "lifecycle": { + "name": "apm-rollover-30-days", + "rollover_alias": "apm-8.0.0-transaction" + }, + "mapping": { + "total_fields": { + "limit": "2000" + } + }, + "number_of_replicas": "1", + "number_of_shards": "1", + "priority": "100", + "refresh_interval": "5s" + } + } + } +} \ No newline at end of file diff --git a/x-pack/test/apm_api_integration/trial/fixtures/es_archiver/ml_8.0.0/data.json.gz b/x-pack/test/apm_api_integration/common/fixtures/es_archiver/ml_8.0.0/data.json.gz similarity index 100% rename from x-pack/test/apm_api_integration/trial/fixtures/es_archiver/ml_8.0.0/data.json.gz rename to x-pack/test/apm_api_integration/common/fixtures/es_archiver/ml_8.0.0/data.json.gz diff --git a/x-pack/test/apm_api_integration/trial/fixtures/es_archiver/ml_8.0.0/mappings.json b/x-pack/test/apm_api_integration/common/fixtures/es_archiver/ml_8.0.0/mappings.json similarity index 100% rename from x-pack/test/apm_api_integration/trial/fixtures/es_archiver/ml_8.0.0/mappings.json rename to x-pack/test/apm_api_integration/common/fixtures/es_archiver/ml_8.0.0/mappings.json diff --git a/x-pack/test/apm_api_integration/basic/fixtures/es_archiver/observability_overview/data.json.gz b/x-pack/test/apm_api_integration/common/fixtures/es_archiver/observability_overview/data.json.gz similarity index 100% rename from x-pack/test/apm_api_integration/basic/fixtures/es_archiver/observability_overview/data.json.gz rename to x-pack/test/apm_api_integration/common/fixtures/es_archiver/observability_overview/data.json.gz diff --git a/x-pack/test/apm_api_integration/basic/fixtures/es_archiver/observability_overview/mappings.json b/x-pack/test/apm_api_integration/common/fixtures/es_archiver/observability_overview/mappings.json similarity index 100% rename from x-pack/test/apm_api_integration/basic/fixtures/es_archiver/observability_overview/mappings.json rename to x-pack/test/apm_api_integration/common/fixtures/es_archiver/observability_overview/mappings.json diff --git a/x-pack/test/apm_api_integration/trial/fixtures/es_archiver/rum_8.0.0/data.json.gz b/x-pack/test/apm_api_integration/common/fixtures/es_archiver/rum_8.0.0/data.json.gz similarity index 100% rename from x-pack/test/apm_api_integration/trial/fixtures/es_archiver/rum_8.0.0/data.json.gz rename to x-pack/test/apm_api_integration/common/fixtures/es_archiver/rum_8.0.0/data.json.gz diff --git a/x-pack/test/apm_api_integration/trial/fixtures/es_archiver/rum_8.0.0/mappings.json b/x-pack/test/apm_api_integration/common/fixtures/es_archiver/rum_8.0.0/mappings.json similarity index 100% rename from x-pack/test/apm_api_integration/trial/fixtures/es_archiver/rum_8.0.0/mappings.json rename to x-pack/test/apm_api_integration/common/fixtures/es_archiver/rum_8.0.0/mappings.json diff --git a/x-pack/test/apm_api_integration/trial/fixtures/es_archiver/8.0.0/data.json.gz b/x-pack/test/apm_api_integration/trial/fixtures/es_archiver/8.0.0/data.json.gz deleted file mode 100644 index e9360878b7bb..000000000000 Binary files a/x-pack/test/apm_api_integration/trial/fixtures/es_archiver/8.0.0/data.json.gz and /dev/null differ diff --git a/x-pack/test/apm_api_integration/trial/fixtures/es_archiver/8.0.0/mappings.json b/x-pack/test/apm_api_integration/trial/fixtures/es_archiver/8.0.0/mappings.json deleted file mode 100644 index 5e9f9f52be8d..000000000000 --- a/x-pack/test/apm_api_integration/trial/fixtures/es_archiver/8.0.0/mappings.json +++ /dev/null @@ -1,25698 +0,0 @@ -{ - "type": "index", - "value": { - "aliases": { - "apm-8.0.0-error": { - "is_write_index": true - } - }, - "index": "apm-8.0.0-error-000001", - "mappings": { - "_meta": { - "beat": "apm", - "version": "8.0.0" - }, - "date_detection": false, - "dynamic_templates": [ - { - "labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "labels.*" - } - }, - { - "container.labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "container.labels.*" - } - }, - { - "dns.answers": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "dns.answers.*" - } - }, - { - "log.syslog": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "log.syslog.*" - } - }, - { - "network.inner": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "network.inner.*" - } - }, - { - "observer.egress": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "observer.egress.*" - } - }, - { - "observer.ingress": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "observer.ingress.*" - } - }, - { - "fields": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "fields.*" - } - }, - { - "docker.container.labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "docker.container.labels.*" - } - }, - { - "kubernetes.labels.*": { - "mapping": { - "type": "keyword" - }, - "path_match": "kubernetes.labels.*" - } - }, - { - "kubernetes.annotations.*": { - "mapping": { - "type": "keyword" - }, - "path_match": "kubernetes.annotations.*" - } - }, - { - "labels_string": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "labels.*" - } - }, - { - "labels_boolean": { - "mapping": { - "type": "boolean" - }, - "match_mapping_type": "boolean", - "path_match": "labels.*" - } - }, - { - "labels_*": { - "mapping": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "path_match": "labels.*" - } - }, - { - "transaction.marks": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "transaction.marks.*" - } - }, - { - "transaction.marks.*.*": { - "mapping": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "path_match": "transaction.marks.*.*" - } - }, - { - "strings_as_keyword": { - "mapping": { - "ignore_above": 1024, - "type": "keyword" - }, - "match_mapping_type": "string" - } - } - ], - "properties": { - "@timestamp": { - "type": "date" - }, - "agent": { - "dynamic": "false", - "properties": { - "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "hostname": { - "path": "agent.name", - "type": "alias" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "child": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "client": { - "dynamic": "false", - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "cloud": { - "properties": { - "account": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "availability_zone": { - "ignore_above": 1024, - "type": "keyword" - }, - "image": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "instance": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "machine": { - "dynamic": "false", - "properties": { - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "project": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "provider": { - "ignore_above": 1024, - "type": "keyword" - }, - "region": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "container": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "image": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "tag": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "labels": { - "type": "object" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "runtime": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "destination": { - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "dll": { - "properties": { - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "dns": { - "properties": { - "answers": { - "properties": { - "class": { - "ignore_above": 1024, - "type": "keyword" - }, - "data": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "ttl": { - "type": "long" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "header_flags": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "op_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "question": { - "properties": { - "class": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "subdomain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "resolved_ip": { - "type": "ip" - }, - "response_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "docker": { - "properties": { - "container": { - "properties": { - "labels": { - "type": "object" - } - } - } - } - }, - "ecs": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "error": { - "dynamic": "false", - "properties": { - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "culprit": { - "ignore_above": 1024, - "type": "keyword" - }, - "exception": { - "properties": { - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "handled": { - "type": "boolean" - }, - "message": { - "norms": false, - "type": "text" - }, - "module": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "grouping_key": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "log": { - "properties": { - "level": { - "ignore_above": 1024, - "type": "keyword" - }, - "logger_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "message": { - "norms": false, - "type": "text" - }, - "param_message": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "message": { - "norms": false, - "type": "text" - }, - "stack_trace": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "event": { - "properties": { - "action": { - "ignore_above": 1024, - "type": "keyword" - }, - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "created": { - "type": "date" - }, - "dataset": { - "ignore_above": 1024, - "type": "keyword" - }, - "duration": { - "type": "long" - }, - "end": { - "type": "date" - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "ingested": { - "type": "date" - }, - "kind": { - "ignore_above": 1024, - "type": "keyword" - }, - "module": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "ignore_above": 1024, - "type": "keyword" - }, - "outcome": { - "ignore_above": 1024, - "type": "keyword" - }, - "provider": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "risk_score": { - "type": "float" - }, - "risk_score_norm": { - "type": "float" - }, - "sequence": { - "type": "long" - }, - "severity": { - "type": "long" - }, - "start": { - "type": "date" - }, - "timezone": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "url": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "experimental": { - "dynamic": "true", - "type": "object" - }, - "fields": { - "type": "object" - }, - "file": { - "properties": { - "accessed": { - "type": "date" - }, - "attributes": { - "ignore_above": 1024, - "type": "keyword" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "created": { - "type": "date" - }, - "ctime": { - "type": "date" - }, - "device": { - "ignore_above": 1024, - "type": "keyword" - }, - "directory": { - "ignore_above": 1024, - "type": "keyword" - }, - "drive_letter": { - "ignore_above": 1, - "type": "keyword" - }, - "extension": { - "ignore_above": 1024, - "type": "keyword" - }, - "gid": { - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "inode": { - "ignore_above": 1024, - "type": "keyword" - }, - "mime_type": { - "ignore_above": 1024, - "type": "keyword" - }, - "mode": { - "ignore_above": 1024, - "type": "keyword" - }, - "mtime": { - "type": "date" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "owner": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "size": { - "type": "long" - }, - "target_path": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "uid": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "host": { - "dynamic": "false", - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "containerized": { - "type": "boolean" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "build": { - "ignore_above": 1024, - "type": "keyword" - }, - "codename": { - "ignore_above": 1024, - "type": "keyword" - }, - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "http": { - "dynamic": "false", - "properties": { - "request": { - "properties": { - "body": { - "properties": { - "bytes": { - "type": "long" - }, - "content": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "bytes": { - "type": "long" - }, - "headers": { - "enabled": false, - "type": "object" - }, - "method": { - "ignore_above": 1024, - "type": "keyword" - }, - "referrer": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "response": { - "properties": { - "body": { - "properties": { - "bytes": { - "type": "long" - }, - "content": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "bytes": { - "type": "long" - }, - "finished": { - "type": "boolean" - }, - "headers": { - "enabled": false, - "type": "object" - }, - "status_code": { - "type": "long" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "kubernetes": { - "dynamic": "false", - "properties": { - "annotations": { - "properties": { - "*": { - "type": "object" - } - } - }, - "container": { - "properties": { - "image": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "deployment": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "labels": { - "properties": { - "*": { - "type": "object" - } - } - }, - "namespace": { - "ignore_above": 1024, - "type": "keyword" - }, - "node": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pod": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "uid": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "replicaset": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "statefulset": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "labels": { - "dynamic": "true", - "properties": { - "foo": { - "type": "keyword" - }, - "lorem": { - "type": "keyword" - }, - "multi-line": { - "type": "keyword" - }, - "this-is-a-very-long-tag-name-without-any-spaces": { - "type": "keyword" - } - } - }, - "log": { - "properties": { - "level": { - "ignore_above": 1024, - "type": "keyword" - }, - "logger": { - "ignore_above": 1024, - "type": "keyword" - }, - "origin": { - "properties": { - "file": { - "properties": { - "line": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "original": { - "ignore_above": 1024, - "type": "keyword" - }, - "syslog": { - "properties": { - "facility": { - "properties": { - "code": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "priority": { - "type": "long" - }, - "severity": { - "properties": { - "code": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - } - } - }, - "message": { - "norms": false, - "type": "text" - }, - "network": { - "properties": { - "application": { - "ignore_above": 1024, - "type": "keyword" - }, - "bytes": { - "type": "long" - }, - "community_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "direction": { - "ignore_above": 1024, - "type": "keyword" - }, - "forwarded_ip": { - "type": "ip" - }, - "iana_number": { - "ignore_above": 1024, - "type": "keyword" - }, - "inner": { - "properties": { - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "packets": { - "type": "long" - }, - "protocol": { - "ignore_above": 1024, - "type": "keyword" - }, - "transport": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "observer": { - "dynamic": "false", - "properties": { - "egress": { - "properties": { - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "zone": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "ingress": { - "properties": { - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "zone": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "listening": { - "ignore_above": 1024, - "type": "keyword" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - }, - "serial_number": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "vendor": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - }, - "version_major": { - "type": "byte" - } - } - }, - "organization": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "package": { - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "build_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "checksum": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "install_scope": { - "ignore_above": 1024, - "type": "keyword" - }, - "installed": { - "type": "date" - }, - "license": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "size": { - "type": "long" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "parent": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "process": { - "dynamic": "false", - "properties": { - "args": { - "ignore_above": 1024, - "type": "keyword" - }, - "args_count": { - "type": "long" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "command_line": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "entity_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "executable": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "exit_code": { - "type": "long" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "parent": { - "properties": { - "args": { - "ignore_above": 1024, - "type": "keyword" - }, - "args_count": { - "type": "long" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "command_line": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "entity_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "executable": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "exit_code": { - "type": "long" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "pgid": { - "type": "long" - }, - "pid": { - "type": "long" - }, - "ppid": { - "type": "long" - }, - "start": { - "type": "date" - }, - "thread": { - "properties": { - "id": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "title": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "working_directory": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pgid": { - "type": "long" - }, - "pid": { - "type": "long" - }, - "ppid": { - "type": "long" - }, - "start": { - "type": "date" - }, - "thread": { - "properties": { - "id": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "title": { - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "working_directory": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "processor": { - "properties": { - "event": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "profile": { - "dynamic": "false", - "properties": { - "alloc_objects": { - "properties": { - "count": { - "type": "long" - } - } - }, - "alloc_space": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "cpu": { - "properties": { - "ns": { - "type": "long" - } - } - }, - "duration": { - "type": "long" - }, - "inuse_objects": { - "properties": { - "count": { - "type": "long" - } - } - }, - "inuse_space": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "samples": { - "properties": { - "count": { - "type": "long" - } - } - }, - "stack": { - "dynamic": "false", - "properties": { - "filename": { - "ignore_above": 1024, - "type": "keyword" - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "line": { - "type": "long" - } - } - }, - "top": { - "dynamic": "false", - "properties": { - "filename": { - "ignore_above": 1024, - "type": "keyword" - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "line": { - "type": "long" - } - } - } - } - }, - "registry": { - "properties": { - "data": { - "properties": { - "bytes": { - "ignore_above": 1024, - "type": "keyword" - }, - "strings": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hive": { - "ignore_above": 1024, - "type": "keyword" - }, - "key": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "value": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "related": { - "properties": { - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "ip": { - "type": "ip" - }, - "user": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "rule": { - "properties": { - "author": { - "ignore_above": 1024, - "type": "keyword" - }, - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "license": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "ruleset": { - "ignore_above": 1024, - "type": "keyword" - }, - "uuid": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "server": { - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "service": { - "dynamic": "false", - "properties": { - "environment": { - "ignore_above": 1024, - "type": "keyword" - }, - "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "framework": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "language": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "node": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "runtime": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "state": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "source": { - "dynamic": "false", - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "sourcemap": { - "dynamic": "false", - "properties": { - "bundle_filepath": { - "ignore_above": 1024, - "type": "keyword" - }, - "service": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "span": { - "dynamic": "false", - "properties": { - "action": { - "ignore_above": 1024, - "type": "keyword" - }, - "db": { - "dynamic": "false", - "properties": { - "link": { - "ignore_above": 1024, - "type": "keyword" - }, - "rows_affected": { - "type": "long" - } - } - }, - "destination": { - "dynamic": "false", - "properties": { - "service": { - "dynamic": "false", - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "resource": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "duration": { - "properties": { - "us": { - "type": "long" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "message": { - "dynamic": "false", - "properties": { - "age": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "queue": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "self_time": { - "properties": { - "count": { - "type": "long" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - } - } - }, - "start": { - "properties": { - "us": { - "type": "long" - } - } - }, - "subtype": { - "ignore_above": 1024, - "type": "keyword" - }, - "sync": { - "type": "boolean" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "system": { - "properties": { - "cpu": { - "properties": { - "total": { - "properties": { - "norm": { - "properties": { - "pct": { - "scaling_factor": 1000, - "type": "scaled_float" - } - } - } - } - } - } - }, - "memory": { - "properties": { - "actual": { - "properties": { - "free": { - "type": "long" - } - } - }, - "total": { - "type": "long" - } - } - }, - "process": { - "properties": { - "cpu": { - "properties": { - "total": { - "properties": { - "norm": { - "properties": { - "pct": { - "scaling_factor": 1000, - "type": "scaled_float" - } - } - } - } - } - } - }, - "memory": { - "properties": { - "rss": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "size": { - "type": "long" - } - } - } - } - } - } - }, - "tags": { - "ignore_above": 1024, - "type": "keyword" - }, - "threat": { - "properties": { - "framework": { - "ignore_above": 1024, - "type": "keyword" - }, - "tactic": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "technique": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "timeseries": { - "properties": { - "instance": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "timestamp": { - "properties": { - "us": { - "type": "long" - } - } - }, - "tls": { - "properties": { - "cipher": { - "ignore_above": 1024, - "type": "keyword" - }, - "client": { - "properties": { - "certificate": { - "ignore_above": 1024, - "type": "keyword" - }, - "certificate_chain": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "issuer": { - "ignore_above": 1024, - "type": "keyword" - }, - "ja3": { - "ignore_above": 1024, - "type": "keyword" - }, - "not_after": { - "type": "date" - }, - "not_before": { - "type": "date" - }, - "server_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject": { - "ignore_above": 1024, - "type": "keyword" - }, - "supported_ciphers": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "curve": { - "ignore_above": 1024, - "type": "keyword" - }, - "established": { - "type": "boolean" - }, - "next_protocol": { - "ignore_above": 1024, - "type": "keyword" - }, - "resumed": { - "type": "boolean" - }, - "server": { - "properties": { - "certificate": { - "ignore_above": 1024, - "type": "keyword" - }, - "certificate_chain": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "issuer": { - "ignore_above": 1024, - "type": "keyword" - }, - "ja3s": { - "ignore_above": 1024, - "type": "keyword" - }, - "not_after": { - "type": "date" - }, - "not_before": { - "type": "date" - }, - "subject": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - }, - "version_protocol": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "trace": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "tracing": { - "properties": { - "trace": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "transaction": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "transaction": { - "dynamic": "false", - "properties": { - "breakdown": { - "properties": { - "count": { - "type": "long" - } - } - }, - "duration": { - "properties": { - "count": { - "type": "long" - }, - "histogram": { - "type": "histogram" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - }, - "us": { - "type": "long" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "marks": { - "dynamic": "true", - "properties": { - "*": { - "properties": { - "*": { - "dynamic": "true", - "type": "object" - } - } - } - } - }, - "message": { - "dynamic": "false", - "properties": { - "age": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "queue": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "result": { - "ignore_above": 1024, - "type": "keyword" - }, - "root": { - "type": "boolean" - }, - "sampled": { - "type": "boolean" - }, - "self_time": { - "properties": { - "count": { - "type": "long" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - } - } - }, - "span_count": { - "properties": { - "dropped": { - "type": "long" - } - } - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "url": { - "dynamic": "false", - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "extension": { - "ignore_above": 1024, - "type": "keyword" - }, - "fragment": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "password": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "port": { - "type": "long" - }, - "query": { - "ignore_above": 1024, - "type": "keyword" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "scheme": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "username": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "user": { - "dynamic": "false", - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "user_agent": { - "dynamic": "false", - "properties": { - "device": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "view spans": { - "ignore_above": 1024, - "type": "keyword" - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vulnerability": { - "properties": { - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "classification": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "enumeration": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "report_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "scanner": { - "properties": { - "vendor": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "score": { - "properties": { - "base": { - "type": "float" - }, - "environmental": { - "type": "float" - }, - "temporal": { - "type": "float" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "severity": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "settings": { - "index": { - "codec": "best_compression", - "lifecycle": { - "name": "apm-rollover-30-days", - "rollover_alias": "apm-8.0.0-error" - }, - "mapping": { - "total_fields": { - "limit": "2000" - } - }, - "number_of_replicas": "0", - "number_of_shards": "1", - "priority": "100", - "query": { - "default_field": [ - "message", - "tags", - "agent.ephemeral_id", - "agent.id", - "agent.name", - "agent.type", - "agent.version", - "as.organization.name", - "client.address", - "client.as.organization.name", - "client.domain", - "client.geo.city_name", - "client.geo.continent_name", - "client.geo.country_iso_code", - "client.geo.country_name", - "client.geo.name", - "client.geo.region_iso_code", - "client.geo.region_name", - "client.mac", - "client.registered_domain", - "client.top_level_domain", - "client.user.domain", - "client.user.email", - "client.user.full_name", - "client.user.group.domain", - "client.user.group.id", - "client.user.group.name", - "client.user.hash", - "client.user.id", - "client.user.name", - "cloud.account.id", - "cloud.availability_zone", - "cloud.instance.id", - "cloud.instance.name", - "cloud.machine.type", - "cloud.provider", - "cloud.region", - "container.id", - "container.image.name", - "container.image.tag", - "container.name", - "container.runtime", - "destination.address", - "destination.as.organization.name", - "destination.domain", - "destination.geo.city_name", - "destination.geo.continent_name", - "destination.geo.country_iso_code", - "destination.geo.country_name", - "destination.geo.name", - "destination.geo.region_iso_code", - "destination.geo.region_name", - "destination.mac", - "destination.registered_domain", - "destination.top_level_domain", - "destination.user.domain", - "destination.user.email", - "destination.user.full_name", - "destination.user.group.domain", - "destination.user.group.id", - "destination.user.group.name", - "destination.user.hash", - "destination.user.id", - "destination.user.name", - "dns.answers.class", - "dns.answers.data", - "dns.answers.name", - "dns.answers.type", - "dns.header_flags", - "dns.id", - "dns.op_code", - "dns.question.class", - "dns.question.name", - "dns.question.registered_domain", - "dns.question.subdomain", - "dns.question.top_level_domain", - "dns.question.type", - "dns.response_code", - "dns.type", - "ecs.version", - "error.code", - "error.id", - "error.message", - "error.stack_trace", - "error.type", - "event.action", - "event.category", - "event.code", - "event.dataset", - "event.hash", - "event.id", - "event.kind", - "event.module", - "event.original", - "event.outcome", - "event.provider", - "event.timezone", - "event.type", - "file.device", - "file.directory", - "file.extension", - "file.gid", - "file.group", - "file.hash.md5", - "file.hash.sha1", - "file.hash.sha256", - "file.hash.sha512", - "file.inode", - "file.mode", - "file.name", - "file.owner", - "file.path", - "file.target_path", - "file.type", - "file.uid", - "geo.city_name", - "geo.continent_name", - "geo.country_iso_code", - "geo.country_name", - "geo.name", - "geo.region_iso_code", - "geo.region_name", - "group.domain", - "group.id", - "group.name", - "hash.md5", - "hash.sha1", - "hash.sha256", - "hash.sha512", - "host.architecture", - "host.geo.city_name", - "host.geo.continent_name", - "host.geo.country_iso_code", - "host.geo.country_name", - "host.geo.name", - "host.geo.region_iso_code", - "host.geo.region_name", - "host.hostname", - "host.id", - "host.mac", - "host.name", - "host.os.family", - "host.os.full", - "host.os.kernel", - "host.os.name", - "host.os.platform", - "host.os.version", - "host.type", - "host.user.domain", - "host.user.email", - "host.user.full_name", - "host.user.group.domain", - "host.user.group.id", - "host.user.group.name", - "host.user.hash", - "host.user.id", - "host.user.name", - "http.request.body.content", - "http.request.method", - "http.request.referrer", - "http.response.body.content", - "http.version", - "log.level", - "log.logger", - "log.origin.file.name", - "log.origin.function", - "log.original", - "log.syslog.facility.name", - "log.syslog.severity.name", - "network.application", - "network.community_id", - "network.direction", - "network.iana_number", - "network.name", - "network.protocol", - "network.transport", - "network.type", - "observer.geo.city_name", - "observer.geo.continent_name", - "observer.geo.country_iso_code", - "observer.geo.country_name", - "observer.geo.name", - "observer.geo.region_iso_code", - "observer.geo.region_name", - "observer.hostname", - "observer.mac", - "observer.name", - "observer.os.family", - "observer.os.full", - "observer.os.kernel", - "observer.os.name", - "observer.os.platform", - "observer.os.version", - "observer.product", - "observer.serial_number", - "observer.type", - "observer.vendor", - "observer.version", - "organization.id", - "organization.name", - "os.family", - "os.full", - "os.kernel", - "os.name", - "os.platform", - "os.version", - "package.architecture", - "package.checksum", - "package.description", - "package.install_scope", - "package.license", - "package.name", - "package.path", - "package.version", - "process.args", - "text", - "process.executable", - "process.hash.md5", - "process.hash.sha1", - "process.hash.sha256", - "process.hash.sha512", - "process.name", - "text", - "text", - "text", - "text", - "text", - "process.thread.name", - "process.title", - "process.working_directory", - "server.address", - "server.as.organization.name", - "server.domain", - "server.geo.city_name", - "server.geo.continent_name", - "server.geo.country_iso_code", - "server.geo.country_name", - "server.geo.name", - "server.geo.region_iso_code", - "server.geo.region_name", - "server.mac", - "server.registered_domain", - "server.top_level_domain", - "server.user.domain", - "server.user.email", - "server.user.full_name", - "server.user.group.domain", - "server.user.group.id", - "server.user.group.name", - "server.user.hash", - "server.user.id", - "server.user.name", - "service.ephemeral_id", - "service.id", - "service.name", - "service.node.name", - "service.state", - "service.type", - "service.version", - "source.address", - "source.as.organization.name", - "source.domain", - "source.geo.city_name", - "source.geo.continent_name", - "source.geo.country_iso_code", - "source.geo.country_name", - "source.geo.name", - "source.geo.region_iso_code", - "source.geo.region_name", - "source.mac", - "source.registered_domain", - "source.top_level_domain", - "source.user.domain", - "source.user.email", - "source.user.full_name", - "source.user.group.domain", - "source.user.group.id", - "source.user.group.name", - "source.user.hash", - "source.user.id", - "source.user.name", - "threat.framework", - "threat.tactic.id", - "threat.tactic.name", - "threat.tactic.reference", - "threat.technique.id", - "threat.technique.name", - "threat.technique.reference", - "tracing.trace.id", - "tracing.transaction.id", - "url.domain", - "url.extension", - "url.fragment", - "url.full", - "url.original", - "url.password", - "url.path", - "url.query", - "url.registered_domain", - "url.scheme", - "url.top_level_domain", - "url.username", - "user.domain", - "user.email", - "user.full_name", - "user.group.domain", - "user.group.id", - "user.group.name", - "user.hash", - "user.id", - "user.name", - "user_agent.device.name", - "user_agent.name", - "text", - "user_agent.original", - "user_agent.os.family", - "user_agent.os.full", - "user_agent.os.kernel", - "user_agent.os.name", - "user_agent.os.platform", - "user_agent.os.version", - "user_agent.version", - "text", - "timeseries.instance", - "cloud.project.id", - "cloud.image.id", - "host.os.build", - "host.os.codename", - "kubernetes.pod.name", - "kubernetes.pod.uid", - "kubernetes.namespace", - "kubernetes.node.name", - "kubernetes.replicaset.name", - "kubernetes.deployment.name", - "kubernetes.statefulset.name", - "kubernetes.container.name", - "kubernetes.container.image", - "processor.name", - "processor.event", - "url.scheme", - "url.full", - "url.domain", - "url.path", - "url.query", - "url.fragment", - "http.version", - "http.request.method", - "http.request.referrer", - "service.name", - "service.version", - "service.environment", - "service.node.name", - "service.language.name", - "service.language.version", - "service.runtime.name", - "service.runtime.version", - "service.framework.name", - "service.framework.version", - "transaction.id", - "transaction.type", - "text", - "transaction.name", - "span.type", - "span.subtype", - "trace.id", - "parent.id", - "agent.name", - "agent.version", - "agent.ephemeral_id", - "container.id", - "kubernetes.namespace", - "kubernetes.node.name", - "kubernetes.pod.name", - "kubernetes.pod.uid", - "host.architecture", - "host.hostname", - "host.name", - "host.os.platform", - "process.args", - "process.title", - "observer.listening", - "observer.hostname", - "observer.version", - "observer.type", - "user.name", - "user.id", - "user.email", - "destination.address", - "text", - "user_agent.original", - "user_agent.name", - "user_agent.version", - "user_agent.device.name", - "user_agent.os.platform", - "user_agent.os.name", - "user_agent.os.full", - "user_agent.os.family", - "user_agent.os.version", - "user_agent.os.kernel", - "cloud.account.id", - "cloud.account.name", - "cloud.availability_zone", - "cloud.instance.id", - "cloud.instance.name", - "cloud.machine.type", - "cloud.project.id", - "cloud.project.name", - "cloud.provider", - "cloud.region", - "error.id", - "error.culprit", - "error.grouping_key", - "error.exception.code", - "error.exception.message", - "error.exception.module", - "error.exception.type", - "error.log.level", - "error.log.logger_name", - "error.log.message", - "error.log.param_message", - "profile.top.id", - "profile.top.function", - "profile.top.filename", - "profile.stack.id", - "profile.stack.function", - "profile.stack.filename", - "sourcemap.service.name", - "sourcemap.service.version", - "sourcemap.bundle_filepath", - "view spans", - "child.id", - "span.id", - "span.name", - "span.action", - "span.db.link", - "span.destination.service.type", - "span.destination.service.name", - "span.destination.service.resource", - "span.message.queue.name", - "transaction.result", - "transaction.message.queue.name", - "fields.*" - ] - }, - "refresh_interval": "1ms" - } - } - } -} - -{ - "type": "index", - "value": { - "aliases": { - "apm-8.0.0-metric": { - "is_write_index": true - } - }, - "index": "apm-8.0.0-metric-000001", - "mappings": { - "_meta": { - "beat": "apm", - "version": "8.0.0" - }, - "date_detection": false, - "dynamic_templates": [ - { - "labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "labels.*" - } - }, - { - "container.labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "container.labels.*" - } - }, - { - "dns.answers": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "dns.answers.*" - } - }, - { - "log.syslog": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "log.syslog.*" - } - }, - { - "network.inner": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "network.inner.*" - } - }, - { - "observer.egress": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "observer.egress.*" - } - }, - { - "observer.ingress": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "observer.ingress.*" - } - }, - { - "fields": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "fields.*" - } - }, - { - "docker.container.labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "docker.container.labels.*" - } - }, - { - "kubernetes.labels.*": { - "mapping": { - "type": "keyword" - }, - "path_match": "kubernetes.labels.*" - } - }, - { - "kubernetes.annotations.*": { - "mapping": { - "type": "keyword" - }, - "path_match": "kubernetes.annotations.*" - } - }, - { - "labels_string": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "labels.*" - } - }, - { - "labels_boolean": { - "mapping": { - "type": "boolean" - }, - "match_mapping_type": "boolean", - "path_match": "labels.*" - } - }, - { - "labels_*": { - "mapping": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "path_match": "labels.*" - } - }, - { - "transaction.marks": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "transaction.marks.*" - } - }, - { - "transaction.marks.*.*": { - "mapping": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "path_match": "transaction.marks.*.*" - } - }, - { - "strings_as_keyword": { - "mapping": { - "ignore_above": 1024, - "type": "keyword" - }, - "match_mapping_type": "string" - } - } - ], - "properties": { - "@timestamp": { - "type": "date" - }, - "agent": { - "dynamic": "false", - "properties": { - "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "hostname": { - "path": "agent.name", - "type": "alias" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "child": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "client": { - "dynamic": "false", - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "cloud": { - "properties": { - "account": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "availability_zone": { - "ignore_above": 1024, - "type": "keyword" - }, - "image": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "instance": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "machine": { - "dynamic": "false", - "properties": { - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "project": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "provider": { - "ignore_above": 1024, - "type": "keyword" - }, - "region": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "container": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "image": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "tag": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "labels": { - "type": "object" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "runtime": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "destination": { - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "dll": { - "properties": { - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "dns": { - "properties": { - "answers": { - "properties": { - "class": { - "ignore_above": 1024, - "type": "keyword" - }, - "data": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "ttl": { - "type": "long" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "header_flags": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "op_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "question": { - "properties": { - "class": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "subdomain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "resolved_ip": { - "type": "ip" - }, - "response_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "docker": { - "properties": { - "container": { - "properties": { - "labels": { - "type": "object" - } - } - } - } - }, - "ecs": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "error": { - "dynamic": "false", - "properties": { - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "culprit": { - "ignore_above": 1024, - "type": "keyword" - }, - "exception": { - "properties": { - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "handled": { - "type": "boolean" - }, - "message": { - "norms": false, - "type": "text" - }, - "module": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "grouping_key": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "log": { - "properties": { - "level": { - "ignore_above": 1024, - "type": "keyword" - }, - "logger_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "message": { - "norms": false, - "type": "text" - }, - "param_message": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "message": { - "norms": false, - "type": "text" - }, - "stack_trace": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "event": { - "properties": { - "action": { - "ignore_above": 1024, - "type": "keyword" - }, - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "created": { - "type": "date" - }, - "dataset": { - "ignore_above": 1024, - "type": "keyword" - }, - "duration": { - "type": "long" - }, - "end": { - "type": "date" - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "ingested": { - "type": "date" - }, - "kind": { - "ignore_above": 1024, - "type": "keyword" - }, - "module": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "ignore_above": 1024, - "type": "keyword" - }, - "outcome": { - "ignore_above": 1024, - "type": "keyword" - }, - "provider": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "risk_score": { - "type": "float" - }, - "risk_score_norm": { - "type": "float" - }, - "sequence": { - "type": "long" - }, - "severity": { - "type": "long" - }, - "start": { - "type": "date" - }, - "timezone": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "url": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "experimental": { - "dynamic": "true", - "type": "object" - }, - "fields": { - "type": "object" - }, - "file": { - "properties": { - "accessed": { - "type": "date" - }, - "attributes": { - "ignore_above": 1024, - "type": "keyword" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "created": { - "type": "date" - }, - "ctime": { - "type": "date" - }, - "device": { - "ignore_above": 1024, - "type": "keyword" - }, - "directory": { - "ignore_above": 1024, - "type": "keyword" - }, - "drive_letter": { - "ignore_above": 1, - "type": "keyword" - }, - "extension": { - "ignore_above": 1024, - "type": "keyword" - }, - "gid": { - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "inode": { - "ignore_above": 1024, - "type": "keyword" - }, - "mime_type": { - "ignore_above": 1024, - "type": "keyword" - }, - "mode": { - "ignore_above": 1024, - "type": "keyword" - }, - "mtime": { - "type": "date" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "owner": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "size": { - "type": "long" - }, - "target_path": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "uid": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "host": { - "dynamic": "false", - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "containerized": { - "type": "boolean" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "build": { - "ignore_above": 1024, - "type": "keyword" - }, - "codename": { - "ignore_above": 1024, - "type": "keyword" - }, - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "http": { - "dynamic": "false", - "properties": { - "request": { - "properties": { - "body": { - "properties": { - "bytes": { - "type": "long" - }, - "content": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "bytes": { - "type": "long" - }, - "headers": { - "enabled": false, - "type": "object" - }, - "method": { - "ignore_above": 1024, - "type": "keyword" - }, - "referrer": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "response": { - "properties": { - "body": { - "properties": { - "bytes": { - "type": "long" - }, - "content": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "bytes": { - "type": "long" - }, - "finished": { - "type": "boolean" - }, - "headers": { - "enabled": false, - "type": "object" - }, - "status_code": { - "type": "long" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "jvm": { - "properties": { - "gc": { - "properties": { - "alloc": { - "type": "float" - }, - "count": { - "type": "long" - }, - "time": { - "type": "long" - } - } - }, - "memory": { - "properties": { - "heap": { - "properties": { - "committed": { - "type": "float" - }, - "max": { - "type": "float" - }, - "used": { - "type": "float" - } - } - }, - "non_heap": { - "properties": { - "committed": { - "type": "float" - }, - "max": { - "type": "long" - }, - "used": { - "type": "float" - } - } - } - } - }, - "thread": { - "properties": { - "count": { - "type": "long" - } - } - } - } - }, - "kubernetes": { - "dynamic": "false", - "properties": { - "annotations": { - "properties": { - "*": { - "type": "object" - } - } - }, - "container": { - "properties": { - "image": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "deployment": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "labels": { - "properties": { - "*": { - "type": "object" - } - } - }, - "namespace": { - "ignore_above": 1024, - "type": "keyword" - }, - "node": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pod": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "uid": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "replicaset": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "statefulset": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "labels": { - "dynamic": "true", - "properties": { - "env": { - "type": "keyword" - }, - "hostname": { - "type": "keyword" - }, - "name": { - "type": "keyword" - } - } - }, - "log": { - "properties": { - "level": { - "ignore_above": 1024, - "type": "keyword" - }, - "logger": { - "ignore_above": 1024, - "type": "keyword" - }, - "origin": { - "properties": { - "file": { - "properties": { - "line": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "original": { - "ignore_above": 1024, - "type": "keyword" - }, - "syslog": { - "properties": { - "facility": { - "properties": { - "code": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "priority": { - "type": "long" - }, - "severity": { - "properties": { - "code": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - } - } - }, - "message": { - "norms": false, - "type": "text" - }, - "network": { - "properties": { - "application": { - "ignore_above": 1024, - "type": "keyword" - }, - "bytes": { - "type": "long" - }, - "community_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "direction": { - "ignore_above": 1024, - "type": "keyword" - }, - "forwarded_ip": { - "type": "ip" - }, - "iana_number": { - "ignore_above": 1024, - "type": "keyword" - }, - "inner": { - "properties": { - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "packets": { - "type": "long" - }, - "protocol": { - "ignore_above": 1024, - "type": "keyword" - }, - "transport": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "nodejs": { - "properties": { - "eventloop": { - "properties": { - "delay": { - "properties": { - "avg": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "ns": { - "type": "long" - } - } - } - } - }, - "handles": { - "properties": { - "active": { - "type": "long" - } - } - }, - "memory": { - "properties": { - "arrayBuffers": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "external": { - "properties": { - "bytes": { - "type": "float" - } - } - }, - "heap": { - "properties": { - "allocated": { - "properties": { - "bytes": { - "type": "float" - } - } - }, - "used": { - "properties": { - "bytes": { - "type": "float" - } - } - } - } - } - } - }, - "requests": { - "properties": { - "active": { - "type": "long" - } - } - } - } - }, - "observer": { - "dynamic": "false", - "properties": { - "egress": { - "properties": { - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "zone": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "ingress": { - "properties": { - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "zone": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "listening": { - "ignore_above": 1024, - "type": "keyword" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - }, - "serial_number": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "vendor": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - }, - "version_major": { - "type": "byte" - } - } - }, - "organization": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "package": { - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "build_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "checksum": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "install_scope": { - "ignore_above": 1024, - "type": "keyword" - }, - "installed": { - "type": "date" - }, - "license": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "size": { - "type": "long" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "parent": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "process": { - "dynamic": "false", - "properties": { - "args": { - "ignore_above": 1024, - "type": "keyword" - }, - "args_count": { - "type": "long" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "command_line": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "entity_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "executable": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "exit_code": { - "type": "long" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "parent": { - "properties": { - "args": { - "ignore_above": 1024, - "type": "keyword" - }, - "args_count": { - "type": "long" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "command_line": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "entity_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "executable": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "exit_code": { - "type": "long" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "pgid": { - "type": "long" - }, - "pid": { - "type": "long" - }, - "ppid": { - "type": "long" - }, - "start": { - "type": "date" - }, - "thread": { - "properties": { - "id": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "title": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "working_directory": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pgid": { - "type": "long" - }, - "pid": { - "type": "long" - }, - "ppid": { - "type": "long" - }, - "start": { - "type": "date" - }, - "thread": { - "properties": { - "id": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "title": { - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "working_directory": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "processor": { - "properties": { - "event": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "profile": { - "dynamic": "false", - "properties": { - "alloc_objects": { - "properties": { - "count": { - "type": "long" - } - } - }, - "alloc_space": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "cpu": { - "properties": { - "ns": { - "type": "long" - } - } - }, - "duration": { - "type": "long" - }, - "inuse_objects": { - "properties": { - "count": { - "type": "long" - } - } - }, - "inuse_space": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "samples": { - "properties": { - "count": { - "type": "long" - } - } - }, - "stack": { - "dynamic": "false", - "properties": { - "filename": { - "ignore_above": 1024, - "type": "keyword" - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "line": { - "type": "long" - } - } - }, - "top": { - "dynamic": "false", - "properties": { - "filename": { - "ignore_above": 1024, - "type": "keyword" - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "line": { - "type": "long" - } - } - } - } - }, - "registry": { - "properties": { - "data": { - "properties": { - "bytes": { - "ignore_above": 1024, - "type": "keyword" - }, - "strings": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hive": { - "ignore_above": 1024, - "type": "keyword" - }, - "key": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "value": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "related": { - "properties": { - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "ip": { - "type": "ip" - }, - "user": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "rule": { - "properties": { - "author": { - "ignore_above": 1024, - "type": "keyword" - }, - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "license": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "ruleset": { - "ignore_above": 1024, - "type": "keyword" - }, - "uuid": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "server": { - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "service": { - "dynamic": "false", - "properties": { - "environment": { - "ignore_above": 1024, - "type": "keyword" - }, - "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "framework": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "language": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "node": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "runtime": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "state": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "source": { - "dynamic": "false", - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "sourcemap": { - "dynamic": "false", - "properties": { - "bundle_filepath": { - "ignore_above": 1024, - "type": "keyword" - }, - "service": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "span": { - "dynamic": "false", - "properties": { - "action": { - "ignore_above": 1024, - "type": "keyword" - }, - "db": { - "dynamic": "false", - "properties": { - "link": { - "ignore_above": 1024, - "type": "keyword" - }, - "rows_affected": { - "type": "long" - } - } - }, - "destination": { - "dynamic": "false", - "properties": { - "service": { - "dynamic": "false", - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "resource": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "duration": { - "properties": { - "us": { - "type": "long" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "message": { - "dynamic": "false", - "properties": { - "age": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "queue": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "self_time": { - "properties": { - "count": { - "type": "long" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - } - } - }, - "start": { - "properties": { - "us": { - "type": "long" - } - } - }, - "subtype": { - "ignore_above": 1024, - "type": "keyword" - }, - "sync": { - "type": "boolean" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "system": { - "properties": { - "cpu": { - "properties": { - "total": { - "properties": { - "norm": { - "properties": { - "pct": { - "scaling_factor": 1000, - "type": "scaled_float" - } - } - } - } - } - } - }, - "memory": { - "properties": { - "actual": { - "properties": { - "free": { - "type": "long" - } - } - }, - "total": { - "type": "long" - } - } - }, - "process": { - "properties": { - "cpu": { - "properties": { - "system": { - "properties": { - "norm": { - "properties": { - "pct": { - "type": "float" - } - } - } - } - }, - "total": { - "properties": { - "norm": { - "properties": { - "pct": { - "scaling_factor": 1000, - "type": "scaled_float" - } - } - } - } - }, - "user": { - "properties": { - "norm": { - "properties": { - "pct": { - "type": "float" - } - } - } - } - } - } - }, - "memory": { - "properties": { - "rss": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "size": { - "type": "long" - } - } - } - } - } - } - }, - "tags": { - "ignore_above": 1024, - "type": "keyword" - }, - "threat": { - "properties": { - "framework": { - "ignore_above": 1024, - "type": "keyword" - }, - "tactic": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "technique": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "timeseries": { - "properties": { - "instance": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "timestamp": { - "properties": { - "us": { - "type": "long" - } - } - }, - "tls": { - "properties": { - "cipher": { - "ignore_above": 1024, - "type": "keyword" - }, - "client": { - "properties": { - "certificate": { - "ignore_above": 1024, - "type": "keyword" - }, - "certificate_chain": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "issuer": { - "ignore_above": 1024, - "type": "keyword" - }, - "ja3": { - "ignore_above": 1024, - "type": "keyword" - }, - "not_after": { - "type": "date" - }, - "not_before": { - "type": "date" - }, - "server_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject": { - "ignore_above": 1024, - "type": "keyword" - }, - "supported_ciphers": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "curve": { - "ignore_above": 1024, - "type": "keyword" - }, - "established": { - "type": "boolean" - }, - "next_protocol": { - "ignore_above": 1024, - "type": "keyword" - }, - "resumed": { - "type": "boolean" - }, - "server": { - "properties": { - "certificate": { - "ignore_above": 1024, - "type": "keyword" - }, - "certificate_chain": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "issuer": { - "ignore_above": 1024, - "type": "keyword" - }, - "ja3s": { - "ignore_above": 1024, - "type": "keyword" - }, - "not_after": { - "type": "date" - }, - "not_before": { - "type": "date" - }, - "subject": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - }, - "version_protocol": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "trace": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "tracing": { - "properties": { - "trace": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "transaction": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "transaction": { - "dynamic": "false", - "properties": { - "breakdown": { - "properties": { - "count": { - "type": "long" - } - } - }, - "duration": { - "properties": { - "count": { - "type": "long" - }, - "histogram": { - "type": "histogram" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - }, - "us": { - "type": "long" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "marks": { - "dynamic": "true", - "properties": { - "*": { - "properties": { - "*": { - "dynamic": "true", - "type": "object" - } - } - } - } - }, - "message": { - "dynamic": "false", - "properties": { - "age": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "queue": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "result": { - "ignore_above": 1024, - "type": "keyword" - }, - "root": { - "type": "boolean" - }, - "sampled": { - "type": "boolean" - }, - "self_time": { - "properties": { - "count": { - "type": "long" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - } - } - }, - "span_count": { - "properties": { - "dropped": { - "type": "long" - } - } - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "url": { - "dynamic": "false", - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "extension": { - "ignore_above": 1024, - "type": "keyword" - }, - "fragment": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "password": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "port": { - "type": "long" - }, - "query": { - "ignore_above": 1024, - "type": "keyword" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "scheme": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "username": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "user": { - "dynamic": "false", - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "user_agent": { - "dynamic": "false", - "properties": { - "device": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "view spans": { - "ignore_above": 1024, - "type": "keyword" - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vulnerability": { - "properties": { - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "classification": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "enumeration": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "report_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "scanner": { - "properties": { - "vendor": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "score": { - "properties": { - "base": { - "type": "float" - }, - "environmental": { - "type": "float" - }, - "temporal": { - "type": "float" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "severity": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "settings": { - "index": { - "codec": "best_compression", - "lifecycle": { - "name": "apm-rollover-30-days", - "rollover_alias": "apm-8.0.0-metric" - }, - "mapping": { - "total_fields": { - "limit": "2000" - } - }, - "number_of_replicas": "0", - "number_of_shards": "1", - "priority": "100", - "query": { - "default_field": [ - "message", - "tags", - "agent.ephemeral_id", - "agent.id", - "agent.name", - "agent.type", - "agent.version", - "as.organization.name", - "client.address", - "client.as.organization.name", - "client.domain", - "client.geo.city_name", - "client.geo.continent_name", - "client.geo.country_iso_code", - "client.geo.country_name", - "client.geo.name", - "client.geo.region_iso_code", - "client.geo.region_name", - "client.mac", - "client.registered_domain", - "client.top_level_domain", - "client.user.domain", - "client.user.email", - "client.user.full_name", - "client.user.group.domain", - "client.user.group.id", - "client.user.group.name", - "client.user.hash", - "client.user.id", - "client.user.name", - "cloud.account.id", - "cloud.availability_zone", - "cloud.instance.id", - "cloud.instance.name", - "cloud.machine.type", - "cloud.provider", - "cloud.region", - "container.id", - "container.image.name", - "container.image.tag", - "container.name", - "container.runtime", - "destination.address", - "destination.as.organization.name", - "destination.domain", - "destination.geo.city_name", - "destination.geo.continent_name", - "destination.geo.country_iso_code", - "destination.geo.country_name", - "destination.geo.name", - "destination.geo.region_iso_code", - "destination.geo.region_name", - "destination.mac", - "destination.registered_domain", - "destination.top_level_domain", - "destination.user.domain", - "destination.user.email", - "destination.user.full_name", - "destination.user.group.domain", - "destination.user.group.id", - "destination.user.group.name", - "destination.user.hash", - "destination.user.id", - "destination.user.name", - "dns.answers.class", - "dns.answers.data", - "dns.answers.name", - "dns.answers.type", - "dns.header_flags", - "dns.id", - "dns.op_code", - "dns.question.class", - "dns.question.name", - "dns.question.registered_domain", - "dns.question.subdomain", - "dns.question.top_level_domain", - "dns.question.type", - "dns.response_code", - "dns.type", - "ecs.version", - "error.code", - "error.id", - "error.message", - "error.stack_trace", - "error.type", - "event.action", - "event.category", - "event.code", - "event.dataset", - "event.hash", - "event.id", - "event.kind", - "event.module", - "event.original", - "event.outcome", - "event.provider", - "event.timezone", - "event.type", - "file.device", - "file.directory", - "file.extension", - "file.gid", - "file.group", - "file.hash.md5", - "file.hash.sha1", - "file.hash.sha256", - "file.hash.sha512", - "file.inode", - "file.mode", - "file.name", - "file.owner", - "file.path", - "file.target_path", - "file.type", - "file.uid", - "geo.city_name", - "geo.continent_name", - "geo.country_iso_code", - "geo.country_name", - "geo.name", - "geo.region_iso_code", - "geo.region_name", - "group.domain", - "group.id", - "group.name", - "hash.md5", - "hash.sha1", - "hash.sha256", - "hash.sha512", - "host.architecture", - "host.geo.city_name", - "host.geo.continent_name", - "host.geo.country_iso_code", - "host.geo.country_name", - "host.geo.name", - "host.geo.region_iso_code", - "host.geo.region_name", - "host.hostname", - "host.id", - "host.mac", - "host.name", - "host.os.family", - "host.os.full", - "host.os.kernel", - "host.os.name", - "host.os.platform", - "host.os.version", - "host.type", - "host.user.domain", - "host.user.email", - "host.user.full_name", - "host.user.group.domain", - "host.user.group.id", - "host.user.group.name", - "host.user.hash", - "host.user.id", - "host.user.name", - "http.request.body.content", - "http.request.method", - "http.request.referrer", - "http.response.body.content", - "http.version", - "log.level", - "log.logger", - "log.origin.file.name", - "log.origin.function", - "log.original", - "log.syslog.facility.name", - "log.syslog.severity.name", - "network.application", - "network.community_id", - "network.direction", - "network.iana_number", - "network.name", - "network.protocol", - "network.transport", - "network.type", - "observer.geo.city_name", - "observer.geo.continent_name", - "observer.geo.country_iso_code", - "observer.geo.country_name", - "observer.geo.name", - "observer.geo.region_iso_code", - "observer.geo.region_name", - "observer.hostname", - "observer.mac", - "observer.name", - "observer.os.family", - "observer.os.full", - "observer.os.kernel", - "observer.os.name", - "observer.os.platform", - "observer.os.version", - "observer.product", - "observer.serial_number", - "observer.type", - "observer.vendor", - "observer.version", - "organization.id", - "organization.name", - "os.family", - "os.full", - "os.kernel", - "os.name", - "os.platform", - "os.version", - "package.architecture", - "package.checksum", - "package.description", - "package.install_scope", - "package.license", - "package.name", - "package.path", - "package.version", - "process.args", - "text", - "process.executable", - "process.hash.md5", - "process.hash.sha1", - "process.hash.sha256", - "process.hash.sha512", - "process.name", - "text", - "text", - "text", - "text", - "text", - "process.thread.name", - "process.title", - "process.working_directory", - "server.address", - "server.as.organization.name", - "server.domain", - "server.geo.city_name", - "server.geo.continent_name", - "server.geo.country_iso_code", - "server.geo.country_name", - "server.geo.name", - "server.geo.region_iso_code", - "server.geo.region_name", - "server.mac", - "server.registered_domain", - "server.top_level_domain", - "server.user.domain", - "server.user.email", - "server.user.full_name", - "server.user.group.domain", - "server.user.group.id", - "server.user.group.name", - "server.user.hash", - "server.user.id", - "server.user.name", - "service.ephemeral_id", - "service.id", - "service.name", - "service.node.name", - "service.state", - "service.type", - "service.version", - "source.address", - "source.as.organization.name", - "source.domain", - "source.geo.city_name", - "source.geo.continent_name", - "source.geo.country_iso_code", - "source.geo.country_name", - "source.geo.name", - "source.geo.region_iso_code", - "source.geo.region_name", - "source.mac", - "source.registered_domain", - "source.top_level_domain", - "source.user.domain", - "source.user.email", - "source.user.full_name", - "source.user.group.domain", - "source.user.group.id", - "source.user.group.name", - "source.user.hash", - "source.user.id", - "source.user.name", - "threat.framework", - "threat.tactic.id", - "threat.tactic.name", - "threat.tactic.reference", - "threat.technique.id", - "threat.technique.name", - "threat.technique.reference", - "tracing.trace.id", - "tracing.transaction.id", - "url.domain", - "url.extension", - "url.fragment", - "url.full", - "url.original", - "url.password", - "url.path", - "url.query", - "url.registered_domain", - "url.scheme", - "url.top_level_domain", - "url.username", - "user.domain", - "user.email", - "user.full_name", - "user.group.domain", - "user.group.id", - "user.group.name", - "user.hash", - "user.id", - "user.name", - "user_agent.device.name", - "user_agent.name", - "text", - "user_agent.original", - "user_agent.os.family", - "user_agent.os.full", - "user_agent.os.kernel", - "user_agent.os.name", - "user_agent.os.platform", - "user_agent.os.version", - "user_agent.version", - "text", - "timeseries.instance", - "cloud.project.id", - "cloud.image.id", - "host.os.build", - "host.os.codename", - "kubernetes.pod.name", - "kubernetes.pod.uid", - "kubernetes.namespace", - "kubernetes.node.name", - "kubernetes.replicaset.name", - "kubernetes.deployment.name", - "kubernetes.statefulset.name", - "kubernetes.container.name", - "kubernetes.container.image", - "processor.name", - "processor.event", - "url.scheme", - "url.full", - "url.domain", - "url.path", - "url.query", - "url.fragment", - "http.version", - "http.request.method", - "http.request.referrer", - "service.name", - "service.version", - "service.environment", - "service.node.name", - "service.language.name", - "service.language.version", - "service.runtime.name", - "service.runtime.version", - "service.framework.name", - "service.framework.version", - "transaction.id", - "transaction.type", - "text", - "transaction.name", - "span.type", - "span.subtype", - "trace.id", - "parent.id", - "agent.name", - "agent.version", - "agent.ephemeral_id", - "container.id", - "kubernetes.namespace", - "kubernetes.node.name", - "kubernetes.pod.name", - "kubernetes.pod.uid", - "host.architecture", - "host.hostname", - "host.name", - "host.os.platform", - "process.args", - "process.title", - "observer.listening", - "observer.hostname", - "observer.version", - "observer.type", - "user.name", - "user.id", - "user.email", - "destination.address", - "text", - "user_agent.original", - "user_agent.name", - "user_agent.version", - "user_agent.device.name", - "user_agent.os.platform", - "user_agent.os.name", - "user_agent.os.full", - "user_agent.os.family", - "user_agent.os.version", - "user_agent.os.kernel", - "cloud.account.id", - "cloud.account.name", - "cloud.availability_zone", - "cloud.instance.id", - "cloud.instance.name", - "cloud.machine.type", - "cloud.project.id", - "cloud.project.name", - "cloud.provider", - "cloud.region", - "error.id", - "error.culprit", - "error.grouping_key", - "error.exception.code", - "error.exception.message", - "error.exception.module", - "error.exception.type", - "error.log.level", - "error.log.logger_name", - "error.log.message", - "error.log.param_message", - "profile.top.id", - "profile.top.function", - "profile.top.filename", - "profile.stack.id", - "profile.stack.function", - "profile.stack.filename", - "sourcemap.service.name", - "sourcemap.service.version", - "sourcemap.bundle_filepath", - "view spans", - "child.id", - "span.id", - "span.name", - "span.action", - "span.db.link", - "span.destination.service.type", - "span.destination.service.name", - "span.destination.service.resource", - "span.message.queue.name", - "transaction.result", - "transaction.message.queue.name", - "fields.*" - ] - }, - "refresh_interval": "1ms" - } - } - } -} - -{ - "type": "index", - "value": { - "aliases": { - }, - "index": "apm-8.0.0-onboarding-2020.06.29", - "mappings": { - "_meta": { - "beat": "apm", - "version": "8.0.0" - }, - "date_detection": false, - "dynamic_templates": [ - { - "labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "labels.*" - } - }, - { - "container.labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "container.labels.*" - } - }, - { - "dns.answers": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "dns.answers.*" - } - }, - { - "log.syslog": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "log.syslog.*" - } - }, - { - "network.inner": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "network.inner.*" - } - }, - { - "observer.egress": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "observer.egress.*" - } - }, - { - "observer.ingress": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "observer.ingress.*" - } - }, - { - "fields": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "fields.*" - } - }, - { - "docker.container.labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "docker.container.labels.*" - } - }, - { - "kubernetes.labels.*": { - "mapping": { - "type": "keyword" - }, - "path_match": "kubernetes.labels.*" - } - }, - { - "kubernetes.annotations.*": { - "mapping": { - "type": "keyword" - }, - "path_match": "kubernetes.annotations.*" - } - }, - { - "labels_string": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "labels.*" - } - }, - { - "labels_boolean": { - "mapping": { - "type": "boolean" - }, - "match_mapping_type": "boolean", - "path_match": "labels.*" - } - }, - { - "labels_*": { - "mapping": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "path_match": "labels.*" - } - }, - { - "transaction.marks": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "transaction.marks.*" - } - }, - { - "transaction.marks.*.*": { - "mapping": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "path_match": "transaction.marks.*.*" - } - }, - { - "strings_as_keyword": { - "mapping": { - "ignore_above": 1024, - "type": "keyword" - }, - "match_mapping_type": "string" - } - } - ], - "properties": { - "@timestamp": { - "type": "date" - }, - "agent": { - "dynamic": "false", - "properties": { - "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "hostname": { - "path": "agent.name", - "type": "alias" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "child": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "client": { - "dynamic": "false", - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "cloud": { - "properties": { - "account": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "availability_zone": { - "ignore_above": 1024, - "type": "keyword" - }, - "image": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "instance": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "machine": { - "dynamic": "false", - "properties": { - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "project": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "provider": { - "ignore_above": 1024, - "type": "keyword" - }, - "region": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "container": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "image": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "tag": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "labels": { - "type": "object" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "runtime": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "destination": { - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "dll": { - "properties": { - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "dns": { - "properties": { - "answers": { - "properties": { - "class": { - "ignore_above": 1024, - "type": "keyword" - }, - "data": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "ttl": { - "type": "long" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "header_flags": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "op_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "question": { - "properties": { - "class": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "subdomain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "resolved_ip": { - "type": "ip" - }, - "response_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "docker": { - "properties": { - "container": { - "properties": { - "labels": { - "type": "object" - } - } - } - } - }, - "ecs": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "error": { - "dynamic": "false", - "properties": { - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "culprit": { - "ignore_above": 1024, - "type": "keyword" - }, - "exception": { - "properties": { - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "handled": { - "type": "boolean" - }, - "message": { - "norms": false, - "type": "text" - }, - "module": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "grouping_key": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "log": { - "properties": { - "level": { - "ignore_above": 1024, - "type": "keyword" - }, - "logger_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "message": { - "norms": false, - "type": "text" - }, - "param_message": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "message": { - "norms": false, - "type": "text" - }, - "stack_trace": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "event": { - "properties": { - "action": { - "ignore_above": 1024, - "type": "keyword" - }, - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "created": { - "type": "date" - }, - "dataset": { - "ignore_above": 1024, - "type": "keyword" - }, - "duration": { - "type": "long" - }, - "end": { - "type": "date" - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "ingested": { - "type": "date" - }, - "kind": { - "ignore_above": 1024, - "type": "keyword" - }, - "module": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "ignore_above": 1024, - "type": "keyword" - }, - "outcome": { - "ignore_above": 1024, - "type": "keyword" - }, - "provider": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "risk_score": { - "type": "float" - }, - "risk_score_norm": { - "type": "float" - }, - "sequence": { - "type": "long" - }, - "severity": { - "type": "long" - }, - "start": { - "type": "date" - }, - "timezone": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "url": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "experimental": { - "dynamic": "true", - "type": "object" - }, - "fields": { - "type": "object" - }, - "file": { - "properties": { - "accessed": { - "type": "date" - }, - "attributes": { - "ignore_above": 1024, - "type": "keyword" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "created": { - "type": "date" - }, - "ctime": { - "type": "date" - }, - "device": { - "ignore_above": 1024, - "type": "keyword" - }, - "directory": { - "ignore_above": 1024, - "type": "keyword" - }, - "drive_letter": { - "ignore_above": 1, - "type": "keyword" - }, - "extension": { - "ignore_above": 1024, - "type": "keyword" - }, - "gid": { - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "inode": { - "ignore_above": 1024, - "type": "keyword" - }, - "mime_type": { - "ignore_above": 1024, - "type": "keyword" - }, - "mode": { - "ignore_above": 1024, - "type": "keyword" - }, - "mtime": { - "type": "date" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "owner": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "size": { - "type": "long" - }, - "target_path": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "uid": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "host": { - "dynamic": "false", - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "containerized": { - "type": "boolean" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "build": { - "ignore_above": 1024, - "type": "keyword" - }, - "codename": { - "ignore_above": 1024, - "type": "keyword" - }, - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "http": { - "dynamic": "false", - "properties": { - "request": { - "properties": { - "body": { - "properties": { - "bytes": { - "type": "long" - }, - "content": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "bytes": { - "type": "long" - }, - "headers": { - "enabled": false, - "type": "object" - }, - "method": { - "ignore_above": 1024, - "type": "keyword" - }, - "referrer": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "response": { - "properties": { - "body": { - "properties": { - "bytes": { - "type": "long" - }, - "content": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "bytes": { - "type": "long" - }, - "finished": { - "type": "boolean" - }, - "headers": { - "enabled": false, - "type": "object" - }, - "status_code": { - "type": "long" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "kubernetes": { - "dynamic": "false", - "properties": { - "annotations": { - "properties": { - "*": { - "type": "object" - } - } - }, - "container": { - "properties": { - "image": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "deployment": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "labels": { - "properties": { - "*": { - "type": "object" - } - } - }, - "namespace": { - "ignore_above": 1024, - "type": "keyword" - }, - "node": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pod": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "uid": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "replicaset": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "statefulset": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "labels": { - "dynamic": "true", - "type": "object" - }, - "log": { - "properties": { - "level": { - "ignore_above": 1024, - "type": "keyword" - }, - "logger": { - "ignore_above": 1024, - "type": "keyword" - }, - "origin": { - "properties": { - "file": { - "properties": { - "line": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "original": { - "ignore_above": 1024, - "type": "keyword" - }, - "syslog": { - "properties": { - "facility": { - "properties": { - "code": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "priority": { - "type": "long" - }, - "severity": { - "properties": { - "code": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - } - } - }, - "message": { - "norms": false, - "type": "text" - }, - "network": { - "properties": { - "application": { - "ignore_above": 1024, - "type": "keyword" - }, - "bytes": { - "type": "long" - }, - "community_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "direction": { - "ignore_above": 1024, - "type": "keyword" - }, - "forwarded_ip": { - "type": "ip" - }, - "iana_number": { - "ignore_above": 1024, - "type": "keyword" - }, - "inner": { - "properties": { - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "packets": { - "type": "long" - }, - "protocol": { - "ignore_above": 1024, - "type": "keyword" - }, - "transport": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "observer": { - "dynamic": "false", - "properties": { - "egress": { - "properties": { - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "zone": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "ingress": { - "properties": { - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "zone": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "listening": { - "ignore_above": 1024, - "type": "keyword" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - }, - "serial_number": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "vendor": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - }, - "version_major": { - "type": "byte" - } - } - }, - "organization": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "package": { - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "build_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "checksum": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "install_scope": { - "ignore_above": 1024, - "type": "keyword" - }, - "installed": { - "type": "date" - }, - "license": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "size": { - "type": "long" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "parent": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "process": { - "dynamic": "false", - "properties": { - "args": { - "ignore_above": 1024, - "type": "keyword" - }, - "args_count": { - "type": "long" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "command_line": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "entity_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "executable": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "exit_code": { - "type": "long" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "parent": { - "properties": { - "args": { - "ignore_above": 1024, - "type": "keyword" - }, - "args_count": { - "type": "long" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "command_line": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "entity_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "executable": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "exit_code": { - "type": "long" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "pgid": { - "type": "long" - }, - "pid": { - "type": "long" - }, - "ppid": { - "type": "long" - }, - "start": { - "type": "date" - }, - "thread": { - "properties": { - "id": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "title": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "working_directory": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pgid": { - "type": "long" - }, - "pid": { - "type": "long" - }, - "ppid": { - "type": "long" - }, - "start": { - "type": "date" - }, - "thread": { - "properties": { - "id": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "title": { - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "working_directory": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "processor": { - "properties": { - "event": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "profile": { - "dynamic": "false", - "properties": { - "alloc_objects": { - "properties": { - "count": { - "type": "long" - } - } - }, - "alloc_space": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "cpu": { - "properties": { - "ns": { - "type": "long" - } - } - }, - "duration": { - "type": "long" - }, - "inuse_objects": { - "properties": { - "count": { - "type": "long" - } - } - }, - "inuse_space": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "samples": { - "properties": { - "count": { - "type": "long" - } - } - }, - "stack": { - "dynamic": "false", - "properties": { - "filename": { - "ignore_above": 1024, - "type": "keyword" - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "line": { - "type": "long" - } - } - }, - "top": { - "dynamic": "false", - "properties": { - "filename": { - "ignore_above": 1024, - "type": "keyword" - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "line": { - "type": "long" - } - } - } - } - }, - "registry": { - "properties": { - "data": { - "properties": { - "bytes": { - "ignore_above": 1024, - "type": "keyword" - }, - "strings": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hive": { - "ignore_above": 1024, - "type": "keyword" - }, - "key": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "value": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "related": { - "properties": { - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "ip": { - "type": "ip" - }, - "user": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "rule": { - "properties": { - "author": { - "ignore_above": 1024, - "type": "keyword" - }, - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "license": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "ruleset": { - "ignore_above": 1024, - "type": "keyword" - }, - "uuid": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "server": { - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "service": { - "dynamic": "false", - "properties": { - "environment": { - "ignore_above": 1024, - "type": "keyword" - }, - "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "framework": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "language": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "node": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "runtime": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "state": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "source": { - "dynamic": "false", - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "sourcemap": { - "dynamic": "false", - "properties": { - "bundle_filepath": { - "ignore_above": 1024, - "type": "keyword" - }, - "service": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "span": { - "dynamic": "false", - "properties": { - "action": { - "ignore_above": 1024, - "type": "keyword" - }, - "db": { - "dynamic": "false", - "properties": { - "link": { - "ignore_above": 1024, - "type": "keyword" - }, - "rows_affected": { - "type": "long" - } - } - }, - "destination": { - "dynamic": "false", - "properties": { - "service": { - "dynamic": "false", - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "resource": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "duration": { - "properties": { - "us": { - "type": "long" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "message": { - "dynamic": "false", - "properties": { - "age": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "queue": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "self_time": { - "properties": { - "count": { - "type": "long" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - } - } - }, - "start": { - "properties": { - "us": { - "type": "long" - } - } - }, - "subtype": { - "ignore_above": 1024, - "type": "keyword" - }, - "sync": { - "type": "boolean" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "system": { - "properties": { - "cpu": { - "properties": { - "total": { - "properties": { - "norm": { - "properties": { - "pct": { - "scaling_factor": 1000, - "type": "scaled_float" - } - } - } - } - } - } - }, - "memory": { - "properties": { - "actual": { - "properties": { - "free": { - "type": "long" - } - } - }, - "total": { - "type": "long" - } - } - }, - "process": { - "properties": { - "cpu": { - "properties": { - "total": { - "properties": { - "norm": { - "properties": { - "pct": { - "scaling_factor": 1000, - "type": "scaled_float" - } - } - } - } - } - } - }, - "memory": { - "properties": { - "rss": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "size": { - "type": "long" - } - } - } - } - } - } - }, - "tags": { - "ignore_above": 1024, - "type": "keyword" - }, - "threat": { - "properties": { - "framework": { - "ignore_above": 1024, - "type": "keyword" - }, - "tactic": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "technique": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "timeseries": { - "properties": { - "instance": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "timestamp": { - "properties": { - "us": { - "type": "long" - } - } - }, - "tls": { - "properties": { - "cipher": { - "ignore_above": 1024, - "type": "keyword" - }, - "client": { - "properties": { - "certificate": { - "ignore_above": 1024, - "type": "keyword" - }, - "certificate_chain": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "issuer": { - "ignore_above": 1024, - "type": "keyword" - }, - "ja3": { - "ignore_above": 1024, - "type": "keyword" - }, - "not_after": { - "type": "date" - }, - "not_before": { - "type": "date" - }, - "server_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject": { - "ignore_above": 1024, - "type": "keyword" - }, - "supported_ciphers": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "curve": { - "ignore_above": 1024, - "type": "keyword" - }, - "established": { - "type": "boolean" - }, - "next_protocol": { - "ignore_above": 1024, - "type": "keyword" - }, - "resumed": { - "type": "boolean" - }, - "server": { - "properties": { - "certificate": { - "ignore_above": 1024, - "type": "keyword" - }, - "certificate_chain": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "issuer": { - "ignore_above": 1024, - "type": "keyword" - }, - "ja3s": { - "ignore_above": 1024, - "type": "keyword" - }, - "not_after": { - "type": "date" - }, - "not_before": { - "type": "date" - }, - "subject": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - }, - "version_protocol": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "trace": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "tracing": { - "properties": { - "trace": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "transaction": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "transaction": { - "dynamic": "false", - "properties": { - "breakdown": { - "properties": { - "count": { - "type": "long" - } - } - }, - "duration": { - "properties": { - "count": { - "type": "long" - }, - "histogram": { - "type": "histogram" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - }, - "us": { - "type": "long" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "marks": { - "dynamic": "true", - "properties": { - "*": { - "properties": { - "*": { - "dynamic": "true", - "type": "object" - } - } - } - } - }, - "message": { - "dynamic": "false", - "properties": { - "age": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "queue": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "result": { - "ignore_above": 1024, - "type": "keyword" - }, - "root": { - "type": "boolean" - }, - "sampled": { - "type": "boolean" - }, - "self_time": { - "properties": { - "count": { - "type": "long" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - } - } - }, - "span_count": { - "properties": { - "dropped": { - "type": "long" - } - } - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "url": { - "dynamic": "false", - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "extension": { - "ignore_above": 1024, - "type": "keyword" - }, - "fragment": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "password": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "port": { - "type": "long" - }, - "query": { - "ignore_above": 1024, - "type": "keyword" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "scheme": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "username": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "user": { - "dynamic": "false", - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "user_agent": { - "dynamic": "false", - "properties": { - "device": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "view spans": { - "ignore_above": 1024, - "type": "keyword" - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vulnerability": { - "properties": { - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "classification": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "enumeration": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "report_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "scanner": { - "properties": { - "vendor": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "score": { - "properties": { - "base": { - "type": "float" - }, - "environmental": { - "type": "float" - }, - "temporal": { - "type": "float" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "severity": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "settings": { - "index": { - "codec": "best_compression", - "mapping": { - "total_fields": { - "limit": "2000" - } - }, - "number_of_replicas": "0", - "number_of_shards": "1", - "query": { - "default_field": [ - "message", - "tags", - "agent.ephemeral_id", - "agent.id", - "agent.name", - "agent.type", - "agent.version", - "as.organization.name", - "client.address", - "client.as.organization.name", - "client.domain", - "client.geo.city_name", - "client.geo.continent_name", - "client.geo.country_iso_code", - "client.geo.country_name", - "client.geo.name", - "client.geo.region_iso_code", - "client.geo.region_name", - "client.mac", - "client.registered_domain", - "client.top_level_domain", - "client.user.domain", - "client.user.email", - "client.user.full_name", - "client.user.group.domain", - "client.user.group.id", - "client.user.group.name", - "client.user.hash", - "client.user.id", - "client.user.name", - "cloud.account.id", - "cloud.availability_zone", - "cloud.instance.id", - "cloud.instance.name", - "cloud.machine.type", - "cloud.provider", - "cloud.region", - "container.id", - "container.image.name", - "container.image.tag", - "container.name", - "container.runtime", - "destination.address", - "destination.as.organization.name", - "destination.domain", - "destination.geo.city_name", - "destination.geo.continent_name", - "destination.geo.country_iso_code", - "destination.geo.country_name", - "destination.geo.name", - "destination.geo.region_iso_code", - "destination.geo.region_name", - "destination.mac", - "destination.registered_domain", - "destination.top_level_domain", - "destination.user.domain", - "destination.user.email", - "destination.user.full_name", - "destination.user.group.domain", - "destination.user.group.id", - "destination.user.group.name", - "destination.user.hash", - "destination.user.id", - "destination.user.name", - "dns.answers.class", - "dns.answers.data", - "dns.answers.name", - "dns.answers.type", - "dns.header_flags", - "dns.id", - "dns.op_code", - "dns.question.class", - "dns.question.name", - "dns.question.registered_domain", - "dns.question.subdomain", - "dns.question.top_level_domain", - "dns.question.type", - "dns.response_code", - "dns.type", - "ecs.version", - "error.code", - "error.id", - "error.message", - "error.stack_trace", - "error.type", - "event.action", - "event.category", - "event.code", - "event.dataset", - "event.hash", - "event.id", - "event.kind", - "event.module", - "event.original", - "event.outcome", - "event.provider", - "event.timezone", - "event.type", - "file.device", - "file.directory", - "file.extension", - "file.gid", - "file.group", - "file.hash.md5", - "file.hash.sha1", - "file.hash.sha256", - "file.hash.sha512", - "file.inode", - "file.mode", - "file.name", - "file.owner", - "file.path", - "file.target_path", - "file.type", - "file.uid", - "geo.city_name", - "geo.continent_name", - "geo.country_iso_code", - "geo.country_name", - "geo.name", - "geo.region_iso_code", - "geo.region_name", - "group.domain", - "group.id", - "group.name", - "hash.md5", - "hash.sha1", - "hash.sha256", - "hash.sha512", - "host.architecture", - "host.geo.city_name", - "host.geo.continent_name", - "host.geo.country_iso_code", - "host.geo.country_name", - "host.geo.name", - "host.geo.region_iso_code", - "host.geo.region_name", - "host.hostname", - "host.id", - "host.mac", - "host.name", - "host.os.family", - "host.os.full", - "host.os.kernel", - "host.os.name", - "host.os.platform", - "host.os.version", - "host.type", - "host.user.domain", - "host.user.email", - "host.user.full_name", - "host.user.group.domain", - "host.user.group.id", - "host.user.group.name", - "host.user.hash", - "host.user.id", - "host.user.name", - "http.request.body.content", - "http.request.method", - "http.request.referrer", - "http.response.body.content", - "http.version", - "log.level", - "log.logger", - "log.origin.file.name", - "log.origin.function", - "log.original", - "log.syslog.facility.name", - "log.syslog.severity.name", - "network.application", - "network.community_id", - "network.direction", - "network.iana_number", - "network.name", - "network.protocol", - "network.transport", - "network.type", - "observer.geo.city_name", - "observer.geo.continent_name", - "observer.geo.country_iso_code", - "observer.geo.country_name", - "observer.geo.name", - "observer.geo.region_iso_code", - "observer.geo.region_name", - "observer.hostname", - "observer.mac", - "observer.name", - "observer.os.family", - "observer.os.full", - "observer.os.kernel", - "observer.os.name", - "observer.os.platform", - "observer.os.version", - "observer.product", - "observer.serial_number", - "observer.type", - "observer.vendor", - "observer.version", - "organization.id", - "organization.name", - "os.family", - "os.full", - "os.kernel", - "os.name", - "os.platform", - "os.version", - "package.architecture", - "package.checksum", - "package.description", - "package.install_scope", - "package.license", - "package.name", - "package.path", - "package.version", - "process.args", - "text", - "process.executable", - "process.hash.md5", - "process.hash.sha1", - "process.hash.sha256", - "process.hash.sha512", - "process.name", - "text", - "text", - "text", - "text", - "text", - "process.thread.name", - "process.title", - "process.working_directory", - "server.address", - "server.as.organization.name", - "server.domain", - "server.geo.city_name", - "server.geo.continent_name", - "server.geo.country_iso_code", - "server.geo.country_name", - "server.geo.name", - "server.geo.region_iso_code", - "server.geo.region_name", - "server.mac", - "server.registered_domain", - "server.top_level_domain", - "server.user.domain", - "server.user.email", - "server.user.full_name", - "server.user.group.domain", - "server.user.group.id", - "server.user.group.name", - "server.user.hash", - "server.user.id", - "server.user.name", - "service.ephemeral_id", - "service.id", - "service.name", - "service.node.name", - "service.state", - "service.type", - "service.version", - "source.address", - "source.as.organization.name", - "source.domain", - "source.geo.city_name", - "source.geo.continent_name", - "source.geo.country_iso_code", - "source.geo.country_name", - "source.geo.name", - "source.geo.region_iso_code", - "source.geo.region_name", - "source.mac", - "source.registered_domain", - "source.top_level_domain", - "source.user.domain", - "source.user.email", - "source.user.full_name", - "source.user.group.domain", - "source.user.group.id", - "source.user.group.name", - "source.user.hash", - "source.user.id", - "source.user.name", - "threat.framework", - "threat.tactic.id", - "threat.tactic.name", - "threat.tactic.reference", - "threat.technique.id", - "threat.technique.name", - "threat.technique.reference", - "tracing.trace.id", - "tracing.transaction.id", - "url.domain", - "url.extension", - "url.fragment", - "url.full", - "url.original", - "url.password", - "url.path", - "url.query", - "url.registered_domain", - "url.scheme", - "url.top_level_domain", - "url.username", - "user.domain", - "user.email", - "user.full_name", - "user.group.domain", - "user.group.id", - "user.group.name", - "user.hash", - "user.id", - "user.name", - "user_agent.device.name", - "user_agent.name", - "text", - "user_agent.original", - "user_agent.os.family", - "user_agent.os.full", - "user_agent.os.kernel", - "user_agent.os.name", - "user_agent.os.platform", - "user_agent.os.version", - "user_agent.version", - "text", - "timeseries.instance", - "cloud.project.id", - "cloud.image.id", - "host.os.build", - "host.os.codename", - "kubernetes.pod.name", - "kubernetes.pod.uid", - "kubernetes.namespace", - "kubernetes.node.name", - "kubernetes.replicaset.name", - "kubernetes.deployment.name", - "kubernetes.statefulset.name", - "kubernetes.container.name", - "kubernetes.container.image", - "processor.name", - "processor.event", - "url.scheme", - "url.full", - "url.domain", - "url.path", - "url.query", - "url.fragment", - "http.version", - "http.request.method", - "http.request.referrer", - "service.name", - "service.version", - "service.environment", - "service.node.name", - "service.language.name", - "service.language.version", - "service.runtime.name", - "service.runtime.version", - "service.framework.name", - "service.framework.version", - "transaction.id", - "transaction.type", - "text", - "transaction.name", - "span.type", - "span.subtype", - "trace.id", - "parent.id", - "agent.name", - "agent.version", - "agent.ephemeral_id", - "container.id", - "kubernetes.namespace", - "kubernetes.node.name", - "kubernetes.pod.name", - "kubernetes.pod.uid", - "host.architecture", - "host.hostname", - "host.name", - "host.os.platform", - "process.args", - "process.title", - "observer.listening", - "observer.hostname", - "observer.version", - "observer.type", - "user.name", - "user.id", - "user.email", - "destination.address", - "text", - "user_agent.original", - "user_agent.name", - "user_agent.version", - "user_agent.device.name", - "user_agent.os.platform", - "user_agent.os.name", - "user_agent.os.full", - "user_agent.os.family", - "user_agent.os.version", - "user_agent.os.kernel", - "cloud.account.id", - "cloud.account.name", - "cloud.availability_zone", - "cloud.instance.id", - "cloud.instance.name", - "cloud.machine.type", - "cloud.project.id", - "cloud.project.name", - "cloud.provider", - "cloud.region", - "error.id", - "error.culprit", - "error.grouping_key", - "error.exception.code", - "error.exception.message", - "error.exception.module", - "error.exception.type", - "error.log.level", - "error.log.logger_name", - "error.log.message", - "error.log.param_message", - "profile.top.id", - "profile.top.function", - "profile.top.filename", - "profile.stack.id", - "profile.stack.function", - "profile.stack.filename", - "sourcemap.service.name", - "sourcemap.service.version", - "sourcemap.bundle_filepath", - "view spans", - "child.id", - "span.id", - "span.name", - "span.action", - "span.db.link", - "span.destination.service.type", - "span.destination.service.name", - "span.destination.service.resource", - "span.message.queue.name", - "transaction.result", - "transaction.message.queue.name", - "fields.*" - ] - }, - "refresh_interval": "1ms" - } - } - } -} - -{ - "type": "index", - "value": { - "aliases": { - "apm-8.0.0-profile": { - "is_write_index": true - } - }, - "index": "apm-8.0.0-profile-000001", - "mappings": { - "_meta": { - "beat": "apm", - "version": "8.0.0" - }, - "date_detection": false, - "dynamic_templates": [ - { - "labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "labels.*" - } - }, - { - "container.labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "container.labels.*" - } - }, - { - "dns.answers": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "dns.answers.*" - } - }, - { - "log.syslog": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "log.syslog.*" - } - }, - { - "network.inner": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "network.inner.*" - } - }, - { - "observer.egress": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "observer.egress.*" - } - }, - { - "observer.ingress": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "observer.ingress.*" - } - }, - { - "fields": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "fields.*" - } - }, - { - "docker.container.labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "docker.container.labels.*" - } - }, - { - "kubernetes.labels.*": { - "mapping": { - "type": "keyword" - }, - "path_match": "kubernetes.labels.*" - } - }, - { - "kubernetes.annotations.*": { - "mapping": { - "type": "keyword" - }, - "path_match": "kubernetes.annotations.*" - } - }, - { - "labels_string": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "labels.*" - } - }, - { - "labels_boolean": { - "mapping": { - "type": "boolean" - }, - "match_mapping_type": "boolean", - "path_match": "labels.*" - } - }, - { - "labels_*": { - "mapping": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "path_match": "labels.*" - } - }, - { - "transaction.marks": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "transaction.marks.*" - } - }, - { - "transaction.marks.*.*": { - "mapping": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "path_match": "transaction.marks.*.*" - } - }, - { - "strings_as_keyword": { - "mapping": { - "ignore_above": 1024, - "type": "keyword" - }, - "match_mapping_type": "string" - } - } - ], - "properties": { - "@timestamp": { - "type": "date" - }, - "agent": { - "dynamic": "false", - "properties": { - "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "hostname": { - "path": "agent.name", - "type": "alias" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "child": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "client": { - "dynamic": "false", - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "cloud": { - "properties": { - "account": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "availability_zone": { - "ignore_above": 1024, - "type": "keyword" - }, - "image": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "instance": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "machine": { - "dynamic": "false", - "properties": { - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "project": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "provider": { - "ignore_above": 1024, - "type": "keyword" - }, - "region": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "container": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "image": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "tag": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "labels": { - "type": "object" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "runtime": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "destination": { - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "dll": { - "properties": { - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "dns": { - "properties": { - "answers": { - "properties": { - "class": { - "ignore_above": 1024, - "type": "keyword" - }, - "data": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "ttl": { - "type": "long" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "header_flags": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "op_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "question": { - "properties": { - "class": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "subdomain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "resolved_ip": { - "type": "ip" - }, - "response_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "docker": { - "properties": { - "container": { - "properties": { - "labels": { - "type": "object" - } - } - } - } - }, - "ecs": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "error": { - "dynamic": "false", - "properties": { - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "culprit": { - "ignore_above": 1024, - "type": "keyword" - }, - "exception": { - "properties": { - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "handled": { - "type": "boolean" - }, - "message": { - "norms": false, - "type": "text" - }, - "module": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "grouping_key": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "log": { - "properties": { - "level": { - "ignore_above": 1024, - "type": "keyword" - }, - "logger_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "message": { - "norms": false, - "type": "text" - }, - "param_message": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "message": { - "norms": false, - "type": "text" - }, - "stack_trace": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "event": { - "properties": { - "action": { - "ignore_above": 1024, - "type": "keyword" - }, - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "created": { - "type": "date" - }, - "dataset": { - "ignore_above": 1024, - "type": "keyword" - }, - "duration": { - "type": "long" - }, - "end": { - "type": "date" - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "ingested": { - "type": "date" - }, - "kind": { - "ignore_above": 1024, - "type": "keyword" - }, - "module": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "ignore_above": 1024, - "type": "keyword" - }, - "outcome": { - "ignore_above": 1024, - "type": "keyword" - }, - "provider": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "risk_score": { - "type": "float" - }, - "risk_score_norm": { - "type": "float" - }, - "sequence": { - "type": "long" - }, - "severity": { - "type": "long" - }, - "start": { - "type": "date" - }, - "timezone": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "url": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "experimental": { - "dynamic": "true", - "type": "object" - }, - "fields": { - "type": "object" - }, - "file": { - "properties": { - "accessed": { - "type": "date" - }, - "attributes": { - "ignore_above": 1024, - "type": "keyword" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "created": { - "type": "date" - }, - "ctime": { - "type": "date" - }, - "device": { - "ignore_above": 1024, - "type": "keyword" - }, - "directory": { - "ignore_above": 1024, - "type": "keyword" - }, - "drive_letter": { - "ignore_above": 1, - "type": "keyword" - }, - "extension": { - "ignore_above": 1024, - "type": "keyword" - }, - "gid": { - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "inode": { - "ignore_above": 1024, - "type": "keyword" - }, - "mime_type": { - "ignore_above": 1024, - "type": "keyword" - }, - "mode": { - "ignore_above": 1024, - "type": "keyword" - }, - "mtime": { - "type": "date" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "owner": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "size": { - "type": "long" - }, - "target_path": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "uid": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "host": { - "dynamic": "false", - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "containerized": { - "type": "boolean" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "build": { - "ignore_above": 1024, - "type": "keyword" - }, - "codename": { - "ignore_above": 1024, - "type": "keyword" - }, - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "http": { - "dynamic": "false", - "properties": { - "request": { - "properties": { - "body": { - "properties": { - "bytes": { - "type": "long" - }, - "content": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "bytes": { - "type": "long" - }, - "headers": { - "enabled": false, - "type": "object" - }, - "method": { - "ignore_above": 1024, - "type": "keyword" - }, - "referrer": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "response": { - "properties": { - "body": { - "properties": { - "bytes": { - "type": "long" - }, - "content": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "bytes": { - "type": "long" - }, - "finished": { - "type": "boolean" - }, - "headers": { - "enabled": false, - "type": "object" - }, - "status_code": { - "type": "long" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "kubernetes": { - "dynamic": "false", - "properties": { - "annotations": { - "properties": { - "*": { - "type": "object" - } - } - }, - "container": { - "properties": { - "image": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "deployment": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "labels": { - "properties": { - "*": { - "type": "object" - } - } - }, - "namespace": { - "ignore_above": 1024, - "type": "keyword" - }, - "node": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pod": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "uid": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "replicaset": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "statefulset": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "labels": { - "dynamic": "true", - "type": "object" - }, - "log": { - "properties": { - "level": { - "ignore_above": 1024, - "type": "keyword" - }, - "logger": { - "ignore_above": 1024, - "type": "keyword" - }, - "origin": { - "properties": { - "file": { - "properties": { - "line": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "original": { - "ignore_above": 1024, - "type": "keyword" - }, - "syslog": { - "properties": { - "facility": { - "properties": { - "code": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "priority": { - "type": "long" - }, - "severity": { - "properties": { - "code": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - } - } - }, - "message": { - "norms": false, - "type": "text" - }, - "network": { - "properties": { - "application": { - "ignore_above": 1024, - "type": "keyword" - }, - "bytes": { - "type": "long" - }, - "community_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "direction": { - "ignore_above": 1024, - "type": "keyword" - }, - "forwarded_ip": { - "type": "ip" - }, - "iana_number": { - "ignore_above": 1024, - "type": "keyword" - }, - "inner": { - "properties": { - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "packets": { - "type": "long" - }, - "protocol": { - "ignore_above": 1024, - "type": "keyword" - }, - "transport": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "observer": { - "dynamic": "false", - "properties": { - "egress": { - "properties": { - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "zone": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "ingress": { - "properties": { - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "zone": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "listening": { - "ignore_above": 1024, - "type": "keyword" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - }, - "serial_number": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "vendor": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - }, - "version_major": { - "type": "byte" - } - } - }, - "organization": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "package": { - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "build_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "checksum": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "install_scope": { - "ignore_above": 1024, - "type": "keyword" - }, - "installed": { - "type": "date" - }, - "license": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "size": { - "type": "long" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "parent": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "process": { - "dynamic": "false", - "properties": { - "args": { - "ignore_above": 1024, - "type": "keyword" - }, - "args_count": { - "type": "long" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "command_line": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "entity_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "executable": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "exit_code": { - "type": "long" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "parent": { - "properties": { - "args": { - "ignore_above": 1024, - "type": "keyword" - }, - "args_count": { - "type": "long" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "command_line": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "entity_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "executable": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "exit_code": { - "type": "long" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "pgid": { - "type": "long" - }, - "pid": { - "type": "long" - }, - "ppid": { - "type": "long" - }, - "start": { - "type": "date" - }, - "thread": { - "properties": { - "id": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "title": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "working_directory": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pgid": { - "type": "long" - }, - "pid": { - "type": "long" - }, - "ppid": { - "type": "long" - }, - "start": { - "type": "date" - }, - "thread": { - "properties": { - "id": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "title": { - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "working_directory": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "processor": { - "properties": { - "event": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "profile": { - "dynamic": "false", - "properties": { - "alloc_objects": { - "properties": { - "count": { - "type": "long" - } - } - }, - "alloc_space": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "cpu": { - "properties": { - "ns": { - "type": "long" - } - } - }, - "duration": { - "type": "long" - }, - "inuse_objects": { - "properties": { - "count": { - "type": "long" - } - } - }, - "inuse_space": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "samples": { - "properties": { - "count": { - "type": "long" - } - } - }, - "stack": { - "dynamic": "false", - "properties": { - "filename": { - "ignore_above": 1024, - "type": "keyword" - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "line": { - "type": "long" - } - } - }, - "top": { - "dynamic": "false", - "properties": { - "filename": { - "ignore_above": 1024, - "type": "keyword" - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "line": { - "type": "long" - } - } - } - } - }, - "registry": { - "properties": { - "data": { - "properties": { - "bytes": { - "ignore_above": 1024, - "type": "keyword" - }, - "strings": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hive": { - "ignore_above": 1024, - "type": "keyword" - }, - "key": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "value": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "related": { - "properties": { - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "ip": { - "type": "ip" - }, - "user": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "rule": { - "properties": { - "author": { - "ignore_above": 1024, - "type": "keyword" - }, - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "license": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "ruleset": { - "ignore_above": 1024, - "type": "keyword" - }, - "uuid": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "server": { - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "service": { - "dynamic": "false", - "properties": { - "environment": { - "ignore_above": 1024, - "type": "keyword" - }, - "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "framework": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "language": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "node": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "runtime": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "state": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "source": { - "dynamic": "false", - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "sourcemap": { - "dynamic": "false", - "properties": { - "bundle_filepath": { - "ignore_above": 1024, - "type": "keyword" - }, - "service": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "span": { - "dynamic": "false", - "properties": { - "action": { - "ignore_above": 1024, - "type": "keyword" - }, - "db": { - "dynamic": "false", - "properties": { - "link": { - "ignore_above": 1024, - "type": "keyword" - }, - "rows_affected": { - "type": "long" - } - } - }, - "destination": { - "dynamic": "false", - "properties": { - "service": { - "dynamic": "false", - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "resource": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "duration": { - "properties": { - "us": { - "type": "long" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "message": { - "dynamic": "false", - "properties": { - "age": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "queue": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "self_time": { - "properties": { - "count": { - "type": "long" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - } - } - }, - "start": { - "properties": { - "us": { - "type": "long" - } - } - }, - "subtype": { - "ignore_above": 1024, - "type": "keyword" - }, - "sync": { - "type": "boolean" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "system": { - "properties": { - "cpu": { - "properties": { - "total": { - "properties": { - "norm": { - "properties": { - "pct": { - "scaling_factor": 1000, - "type": "scaled_float" - } - } - } - } - } - } - }, - "memory": { - "properties": { - "actual": { - "properties": { - "free": { - "type": "long" - } - } - }, - "total": { - "type": "long" - } - } - }, - "process": { - "properties": { - "cpu": { - "properties": { - "total": { - "properties": { - "norm": { - "properties": { - "pct": { - "scaling_factor": 1000, - "type": "scaled_float" - } - } - } - } - } - } - }, - "memory": { - "properties": { - "rss": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "size": { - "type": "long" - } - } - } - } - } - } - }, - "tags": { - "ignore_above": 1024, - "type": "keyword" - }, - "threat": { - "properties": { - "framework": { - "ignore_above": 1024, - "type": "keyword" - }, - "tactic": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "technique": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "timeseries": { - "properties": { - "instance": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "timestamp": { - "properties": { - "us": { - "type": "long" - } - } - }, - "tls": { - "properties": { - "cipher": { - "ignore_above": 1024, - "type": "keyword" - }, - "client": { - "properties": { - "certificate": { - "ignore_above": 1024, - "type": "keyword" - }, - "certificate_chain": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "issuer": { - "ignore_above": 1024, - "type": "keyword" - }, - "ja3": { - "ignore_above": 1024, - "type": "keyword" - }, - "not_after": { - "type": "date" - }, - "not_before": { - "type": "date" - }, - "server_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject": { - "ignore_above": 1024, - "type": "keyword" - }, - "supported_ciphers": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "curve": { - "ignore_above": 1024, - "type": "keyword" - }, - "established": { - "type": "boolean" - }, - "next_protocol": { - "ignore_above": 1024, - "type": "keyword" - }, - "resumed": { - "type": "boolean" - }, - "server": { - "properties": { - "certificate": { - "ignore_above": 1024, - "type": "keyword" - }, - "certificate_chain": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "issuer": { - "ignore_above": 1024, - "type": "keyword" - }, - "ja3s": { - "ignore_above": 1024, - "type": "keyword" - }, - "not_after": { - "type": "date" - }, - "not_before": { - "type": "date" - }, - "subject": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - }, - "version_protocol": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "trace": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "tracing": { - "properties": { - "trace": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "transaction": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "transaction": { - "dynamic": "false", - "properties": { - "breakdown": { - "properties": { - "count": { - "type": "long" - } - } - }, - "duration": { - "properties": { - "count": { - "type": "long" - }, - "histogram": { - "type": "histogram" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - }, - "us": { - "type": "long" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "marks": { - "dynamic": "true", - "properties": { - "*": { - "properties": { - "*": { - "dynamic": "true", - "type": "object" - } - } - } - } - }, - "message": { - "dynamic": "false", - "properties": { - "age": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "queue": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "result": { - "ignore_above": 1024, - "type": "keyword" - }, - "root": { - "type": "boolean" - }, - "sampled": { - "type": "boolean" - }, - "self_time": { - "properties": { - "count": { - "type": "long" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - } - } - }, - "span_count": { - "properties": { - "dropped": { - "type": "long" - } - } - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "url": { - "dynamic": "false", - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "extension": { - "ignore_above": 1024, - "type": "keyword" - }, - "fragment": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "password": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "port": { - "type": "long" - }, - "query": { - "ignore_above": 1024, - "type": "keyword" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "scheme": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "username": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "user": { - "dynamic": "false", - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "user_agent": { - "dynamic": "false", - "properties": { - "device": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "view spans": { - "ignore_above": 1024, - "type": "keyword" - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vulnerability": { - "properties": { - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "classification": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "enumeration": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "report_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "scanner": { - "properties": { - "vendor": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "score": { - "properties": { - "base": { - "type": "float" - }, - "environmental": { - "type": "float" - }, - "temporal": { - "type": "float" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "severity": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "settings": { - "index": { - "codec": "best_compression", - "lifecycle": { - "name": "apm-rollover-30-days", - "rollover_alias": "apm-8.0.0-profile" - }, - "mapping": { - "total_fields": { - "limit": "2000" - } - }, - "number_of_replicas": "0", - "number_of_shards": "1", - "priority": "100", - "query": { - "default_field": [ - "message", - "tags", - "agent.ephemeral_id", - "agent.id", - "agent.name", - "agent.type", - "agent.version", - "as.organization.name", - "client.address", - "client.as.organization.name", - "client.domain", - "client.geo.city_name", - "client.geo.continent_name", - "client.geo.country_iso_code", - "client.geo.country_name", - "client.geo.name", - "client.geo.region_iso_code", - "client.geo.region_name", - "client.mac", - "client.registered_domain", - "client.top_level_domain", - "client.user.domain", - "client.user.email", - "client.user.full_name", - "client.user.group.domain", - "client.user.group.id", - "client.user.group.name", - "client.user.hash", - "client.user.id", - "client.user.name", - "cloud.account.id", - "cloud.availability_zone", - "cloud.instance.id", - "cloud.instance.name", - "cloud.machine.type", - "cloud.provider", - "cloud.region", - "container.id", - "container.image.name", - "container.image.tag", - "container.name", - "container.runtime", - "destination.address", - "destination.as.organization.name", - "destination.domain", - "destination.geo.city_name", - "destination.geo.continent_name", - "destination.geo.country_iso_code", - "destination.geo.country_name", - "destination.geo.name", - "destination.geo.region_iso_code", - "destination.geo.region_name", - "destination.mac", - "destination.registered_domain", - "destination.top_level_domain", - "destination.user.domain", - "destination.user.email", - "destination.user.full_name", - "destination.user.group.domain", - "destination.user.group.id", - "destination.user.group.name", - "destination.user.hash", - "destination.user.id", - "destination.user.name", - "dns.answers.class", - "dns.answers.data", - "dns.answers.name", - "dns.answers.type", - "dns.header_flags", - "dns.id", - "dns.op_code", - "dns.question.class", - "dns.question.name", - "dns.question.registered_domain", - "dns.question.subdomain", - "dns.question.top_level_domain", - "dns.question.type", - "dns.response_code", - "dns.type", - "ecs.version", - "error.code", - "error.id", - "error.message", - "error.stack_trace", - "error.type", - "event.action", - "event.category", - "event.code", - "event.dataset", - "event.hash", - "event.id", - "event.kind", - "event.module", - "event.original", - "event.outcome", - "event.provider", - "event.timezone", - "event.type", - "file.device", - "file.directory", - "file.extension", - "file.gid", - "file.group", - "file.hash.md5", - "file.hash.sha1", - "file.hash.sha256", - "file.hash.sha512", - "file.inode", - "file.mode", - "file.name", - "file.owner", - "file.path", - "file.target_path", - "file.type", - "file.uid", - "geo.city_name", - "geo.continent_name", - "geo.country_iso_code", - "geo.country_name", - "geo.name", - "geo.region_iso_code", - "geo.region_name", - "group.domain", - "group.id", - "group.name", - "hash.md5", - "hash.sha1", - "hash.sha256", - "hash.sha512", - "host.architecture", - "host.geo.city_name", - "host.geo.continent_name", - "host.geo.country_iso_code", - "host.geo.country_name", - "host.geo.name", - "host.geo.region_iso_code", - "host.geo.region_name", - "host.hostname", - "host.id", - "host.mac", - "host.name", - "host.os.family", - "host.os.full", - "host.os.kernel", - "host.os.name", - "host.os.platform", - "host.os.version", - "host.type", - "host.user.domain", - "host.user.email", - "host.user.full_name", - "host.user.group.domain", - "host.user.group.id", - "host.user.group.name", - "host.user.hash", - "host.user.id", - "host.user.name", - "http.request.body.content", - "http.request.method", - "http.request.referrer", - "http.response.body.content", - "http.version", - "log.level", - "log.logger", - "log.origin.file.name", - "log.origin.function", - "log.original", - "log.syslog.facility.name", - "log.syslog.severity.name", - "network.application", - "network.community_id", - "network.direction", - "network.iana_number", - "network.name", - "network.protocol", - "network.transport", - "network.type", - "observer.geo.city_name", - "observer.geo.continent_name", - "observer.geo.country_iso_code", - "observer.geo.country_name", - "observer.geo.name", - "observer.geo.region_iso_code", - "observer.geo.region_name", - "observer.hostname", - "observer.mac", - "observer.name", - "observer.os.family", - "observer.os.full", - "observer.os.kernel", - "observer.os.name", - "observer.os.platform", - "observer.os.version", - "observer.product", - "observer.serial_number", - "observer.type", - "observer.vendor", - "observer.version", - "organization.id", - "organization.name", - "os.family", - "os.full", - "os.kernel", - "os.name", - "os.platform", - "os.version", - "package.architecture", - "package.checksum", - "package.description", - "package.install_scope", - "package.license", - "package.name", - "package.path", - "package.version", - "process.args", - "text", - "process.executable", - "process.hash.md5", - "process.hash.sha1", - "process.hash.sha256", - "process.hash.sha512", - "process.name", - "text", - "text", - "text", - "text", - "text", - "process.thread.name", - "process.title", - "process.working_directory", - "server.address", - "server.as.organization.name", - "server.domain", - "server.geo.city_name", - "server.geo.continent_name", - "server.geo.country_iso_code", - "server.geo.country_name", - "server.geo.name", - "server.geo.region_iso_code", - "server.geo.region_name", - "server.mac", - "server.registered_domain", - "server.top_level_domain", - "server.user.domain", - "server.user.email", - "server.user.full_name", - "server.user.group.domain", - "server.user.group.id", - "server.user.group.name", - "server.user.hash", - "server.user.id", - "server.user.name", - "service.ephemeral_id", - "service.id", - "service.name", - "service.node.name", - "service.state", - "service.type", - "service.version", - "source.address", - "source.as.organization.name", - "source.domain", - "source.geo.city_name", - "source.geo.continent_name", - "source.geo.country_iso_code", - "source.geo.country_name", - "source.geo.name", - "source.geo.region_iso_code", - "source.geo.region_name", - "source.mac", - "source.registered_domain", - "source.top_level_domain", - "source.user.domain", - "source.user.email", - "source.user.full_name", - "source.user.group.domain", - "source.user.group.id", - "source.user.group.name", - "source.user.hash", - "source.user.id", - "source.user.name", - "threat.framework", - "threat.tactic.id", - "threat.tactic.name", - "threat.tactic.reference", - "threat.technique.id", - "threat.technique.name", - "threat.technique.reference", - "tracing.trace.id", - "tracing.transaction.id", - "url.domain", - "url.extension", - "url.fragment", - "url.full", - "url.original", - "url.password", - "url.path", - "url.query", - "url.registered_domain", - "url.scheme", - "url.top_level_domain", - "url.username", - "user.domain", - "user.email", - "user.full_name", - "user.group.domain", - "user.group.id", - "user.group.name", - "user.hash", - "user.id", - "user.name", - "user_agent.device.name", - "user_agent.name", - "text", - "user_agent.original", - "user_agent.os.family", - "user_agent.os.full", - "user_agent.os.kernel", - "user_agent.os.name", - "user_agent.os.platform", - "user_agent.os.version", - "user_agent.version", - "text", - "timeseries.instance", - "cloud.project.id", - "cloud.image.id", - "host.os.build", - "host.os.codename", - "kubernetes.pod.name", - "kubernetes.pod.uid", - "kubernetes.namespace", - "kubernetes.node.name", - "kubernetes.replicaset.name", - "kubernetes.deployment.name", - "kubernetes.statefulset.name", - "kubernetes.container.name", - "kubernetes.container.image", - "processor.name", - "processor.event", - "url.scheme", - "url.full", - "url.domain", - "url.path", - "url.query", - "url.fragment", - "http.version", - "http.request.method", - "http.request.referrer", - "service.name", - "service.version", - "service.environment", - "service.node.name", - "service.language.name", - "service.language.version", - "service.runtime.name", - "service.runtime.version", - "service.framework.name", - "service.framework.version", - "transaction.id", - "transaction.type", - "text", - "transaction.name", - "span.type", - "span.subtype", - "trace.id", - "parent.id", - "agent.name", - "agent.version", - "agent.ephemeral_id", - "container.id", - "kubernetes.namespace", - "kubernetes.node.name", - "kubernetes.pod.name", - "kubernetes.pod.uid", - "host.architecture", - "host.hostname", - "host.name", - "host.os.platform", - "process.args", - "process.title", - "observer.listening", - "observer.hostname", - "observer.version", - "observer.type", - "user.name", - "user.id", - "user.email", - "destination.address", - "text", - "user_agent.original", - "user_agent.name", - "user_agent.version", - "user_agent.device.name", - "user_agent.os.platform", - "user_agent.os.name", - "user_agent.os.full", - "user_agent.os.family", - "user_agent.os.version", - "user_agent.os.kernel", - "cloud.account.id", - "cloud.account.name", - "cloud.availability_zone", - "cloud.instance.id", - "cloud.instance.name", - "cloud.machine.type", - "cloud.project.id", - "cloud.project.name", - "cloud.provider", - "cloud.region", - "error.id", - "error.culprit", - "error.grouping_key", - "error.exception.code", - "error.exception.message", - "error.exception.module", - "error.exception.type", - "error.log.level", - "error.log.logger_name", - "error.log.message", - "error.log.param_message", - "profile.top.id", - "profile.top.function", - "profile.top.filename", - "profile.stack.id", - "profile.stack.function", - "profile.stack.filename", - "sourcemap.service.name", - "sourcemap.service.version", - "sourcemap.bundle_filepath", - "view spans", - "child.id", - "span.id", - "span.name", - "span.action", - "span.db.link", - "span.destination.service.type", - "span.destination.service.name", - "span.destination.service.resource", - "span.message.queue.name", - "transaction.result", - "transaction.message.queue.name", - "fields.*" - ] - }, - "refresh_interval": "1ms" - } - } - } -} - -{ - "type": "index", - "value": { - "aliases": { - "apm-8.0.0-span": { - "is_write_index": true - } - }, - "index": "apm-8.0.0-span-000001", - "mappings": { - "_meta": { - "beat": "apm", - "version": "8.0.0" - }, - "date_detection": false, - "dynamic_templates": [ - { - "labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "labels.*" - } - }, - { - "container.labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "container.labels.*" - } - }, - { - "dns.answers": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "dns.answers.*" - } - }, - { - "log.syslog": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "log.syslog.*" - } - }, - { - "network.inner": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "network.inner.*" - } - }, - { - "observer.egress": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "observer.egress.*" - } - }, - { - "observer.ingress": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "observer.ingress.*" - } - }, - { - "fields": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "fields.*" - } - }, - { - "docker.container.labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "docker.container.labels.*" - } - }, - { - "kubernetes.labels.*": { - "mapping": { - "type": "keyword" - }, - "path_match": "kubernetes.labels.*" - } - }, - { - "kubernetes.annotations.*": { - "mapping": { - "type": "keyword" - }, - "path_match": "kubernetes.annotations.*" - } - }, - { - "labels_string": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "labels.*" - } - }, - { - "labels_boolean": { - "mapping": { - "type": "boolean" - }, - "match_mapping_type": "boolean", - "path_match": "labels.*" - } - }, - { - "labels_*": { - "mapping": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "path_match": "labels.*" - } - }, - { - "transaction.marks": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "transaction.marks.*" - } - }, - { - "transaction.marks.*.*": { - "mapping": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "path_match": "transaction.marks.*.*" - } - }, - { - "strings_as_keyword": { - "mapping": { - "ignore_above": 1024, - "type": "keyword" - }, - "match_mapping_type": "string" - } - } - ], - "properties": { - "@timestamp": { - "type": "date" - }, - "agent": { - "dynamic": "false", - "properties": { - "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "hostname": { - "path": "agent.name", - "type": "alias" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "child": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "client": { - "dynamic": "false", - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "cloud": { - "properties": { - "account": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "availability_zone": { - "ignore_above": 1024, - "type": "keyword" - }, - "image": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "instance": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "machine": { - "dynamic": "false", - "properties": { - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "project": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "provider": { - "ignore_above": 1024, - "type": "keyword" - }, - "region": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "container": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "image": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "tag": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "labels": { - "type": "object" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "runtime": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "destination": { - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "dll": { - "properties": { - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "dns": { - "properties": { - "answers": { - "properties": { - "class": { - "ignore_above": 1024, - "type": "keyword" - }, - "data": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "ttl": { - "type": "long" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "header_flags": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "op_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "question": { - "properties": { - "class": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "subdomain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "resolved_ip": { - "type": "ip" - }, - "response_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "docker": { - "properties": { - "container": { - "properties": { - "labels": { - "type": "object" - } - } - } - } - }, - "ecs": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "error": { - "dynamic": "false", - "properties": { - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "culprit": { - "ignore_above": 1024, - "type": "keyword" - }, - "exception": { - "properties": { - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "handled": { - "type": "boolean" - }, - "message": { - "norms": false, - "type": "text" - }, - "module": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "grouping_key": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "log": { - "properties": { - "level": { - "ignore_above": 1024, - "type": "keyword" - }, - "logger_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "message": { - "norms": false, - "type": "text" - }, - "param_message": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "message": { - "norms": false, - "type": "text" - }, - "stack_trace": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "event": { - "properties": { - "action": { - "ignore_above": 1024, - "type": "keyword" - }, - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "created": { - "type": "date" - }, - "dataset": { - "ignore_above": 1024, - "type": "keyword" - }, - "duration": { - "type": "long" - }, - "end": { - "type": "date" - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "ingested": { - "type": "date" - }, - "kind": { - "ignore_above": 1024, - "type": "keyword" - }, - "module": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "ignore_above": 1024, - "type": "keyword" - }, - "outcome": { - "ignore_above": 1024, - "type": "keyword" - }, - "provider": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "risk_score": { - "type": "float" - }, - "risk_score_norm": { - "type": "float" - }, - "sequence": { - "type": "long" - }, - "severity": { - "type": "long" - }, - "start": { - "type": "date" - }, - "timezone": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "url": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "experimental": { - "dynamic": "true", - "type": "object" - }, - "fields": { - "type": "object" - }, - "file": { - "properties": { - "accessed": { - "type": "date" - }, - "attributes": { - "ignore_above": 1024, - "type": "keyword" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "created": { - "type": "date" - }, - "ctime": { - "type": "date" - }, - "device": { - "ignore_above": 1024, - "type": "keyword" - }, - "directory": { - "ignore_above": 1024, - "type": "keyword" - }, - "drive_letter": { - "ignore_above": 1, - "type": "keyword" - }, - "extension": { - "ignore_above": 1024, - "type": "keyword" - }, - "gid": { - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "inode": { - "ignore_above": 1024, - "type": "keyword" - }, - "mime_type": { - "ignore_above": 1024, - "type": "keyword" - }, - "mode": { - "ignore_above": 1024, - "type": "keyword" - }, - "mtime": { - "type": "date" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "owner": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "size": { - "type": "long" - }, - "target_path": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "uid": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "host": { - "dynamic": "false", - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "containerized": { - "type": "boolean" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "build": { - "ignore_above": 1024, - "type": "keyword" - }, - "codename": { - "ignore_above": 1024, - "type": "keyword" - }, - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "http": { - "dynamic": "false", - "properties": { - "request": { - "properties": { - "body": { - "properties": { - "bytes": { - "type": "long" - }, - "content": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "bytes": { - "type": "long" - }, - "headers": { - "enabled": false, - "type": "object" - }, - "method": { - "ignore_above": 1024, - "type": "keyword" - }, - "referrer": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "response": { - "properties": { - "body": { - "properties": { - "bytes": { - "type": "long" - }, - "content": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "bytes": { - "type": "long" - }, - "finished": { - "type": "boolean" - }, - "headers": { - "enabled": false, - "type": "object" - }, - "status_code": { - "type": "long" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "kubernetes": { - "dynamic": "false", - "properties": { - "annotations": { - "properties": { - "*": { - "type": "object" - } - } - }, - "container": { - "properties": { - "image": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "deployment": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "labels": { - "properties": { - "*": { - "type": "object" - } - } - }, - "namespace": { - "ignore_above": 1024, - "type": "keyword" - }, - "node": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pod": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "uid": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "replicaset": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "statefulset": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "labels": { - "dynamic": "true", - "properties": { - "foo": { - "type": "keyword" - }, - "productId": { - "type": "keyword" - } - } - }, - "log": { - "properties": { - "level": { - "ignore_above": 1024, - "type": "keyword" - }, - "logger": { - "ignore_above": 1024, - "type": "keyword" - }, - "origin": { - "properties": { - "file": { - "properties": { - "line": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "original": { - "ignore_above": 1024, - "type": "keyword" - }, - "syslog": { - "properties": { - "facility": { - "properties": { - "code": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "priority": { - "type": "long" - }, - "severity": { - "properties": { - "code": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - } - } - }, - "message": { - "norms": false, - "type": "text" - }, - "network": { - "properties": { - "application": { - "ignore_above": 1024, - "type": "keyword" - }, - "bytes": { - "type": "long" - }, - "community_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "direction": { - "ignore_above": 1024, - "type": "keyword" - }, - "forwarded_ip": { - "type": "ip" - }, - "iana_number": { - "ignore_above": 1024, - "type": "keyword" - }, - "inner": { - "properties": { - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "packets": { - "type": "long" - }, - "protocol": { - "ignore_above": 1024, - "type": "keyword" - }, - "transport": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "observer": { - "dynamic": "false", - "properties": { - "egress": { - "properties": { - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "zone": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "ingress": { - "properties": { - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "zone": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "listening": { - "ignore_above": 1024, - "type": "keyword" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - }, - "serial_number": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "vendor": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - }, - "version_major": { - "type": "byte" - } - } - }, - "organization": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "package": { - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "build_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "checksum": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "install_scope": { - "ignore_above": 1024, - "type": "keyword" - }, - "installed": { - "type": "date" - }, - "license": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "size": { - "type": "long" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "parent": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "process": { - "dynamic": "false", - "properties": { - "args": { - "ignore_above": 1024, - "type": "keyword" - }, - "args_count": { - "type": "long" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "command_line": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "entity_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "executable": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "exit_code": { - "type": "long" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "parent": { - "properties": { - "args": { - "ignore_above": 1024, - "type": "keyword" - }, - "args_count": { - "type": "long" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "command_line": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "entity_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "executable": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "exit_code": { - "type": "long" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "pgid": { - "type": "long" - }, - "pid": { - "type": "long" - }, - "ppid": { - "type": "long" - }, - "start": { - "type": "date" - }, - "thread": { - "properties": { - "id": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "title": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "working_directory": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pgid": { - "type": "long" - }, - "pid": { - "type": "long" - }, - "ppid": { - "type": "long" - }, - "start": { - "type": "date" - }, - "thread": { - "properties": { - "id": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "title": { - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "working_directory": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "processor": { - "properties": { - "event": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "profile": { - "dynamic": "false", - "properties": { - "alloc_objects": { - "properties": { - "count": { - "type": "long" - } - } - }, - "alloc_space": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "cpu": { - "properties": { - "ns": { - "type": "long" - } - } - }, - "duration": { - "type": "long" - }, - "inuse_objects": { - "properties": { - "count": { - "type": "long" - } - } - }, - "inuse_space": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "samples": { - "properties": { - "count": { - "type": "long" - } - } - }, - "stack": { - "dynamic": "false", - "properties": { - "filename": { - "ignore_above": 1024, - "type": "keyword" - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "line": { - "type": "long" - } - } - }, - "top": { - "dynamic": "false", - "properties": { - "filename": { - "ignore_above": 1024, - "type": "keyword" - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "line": { - "type": "long" - } - } - } - } - }, - "registry": { - "properties": { - "data": { - "properties": { - "bytes": { - "ignore_above": 1024, - "type": "keyword" - }, - "strings": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hive": { - "ignore_above": 1024, - "type": "keyword" - }, - "key": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "value": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "related": { - "properties": { - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "ip": { - "type": "ip" - }, - "user": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "rule": { - "properties": { - "author": { - "ignore_above": 1024, - "type": "keyword" - }, - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "license": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "ruleset": { - "ignore_above": 1024, - "type": "keyword" - }, - "uuid": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "server": { - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "service": { - "dynamic": "false", - "properties": { - "environment": { - "ignore_above": 1024, - "type": "keyword" - }, - "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "framework": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "language": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "node": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "runtime": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "state": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "source": { - "dynamic": "false", - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "sourcemap": { - "dynamic": "false", - "properties": { - "bundle_filepath": { - "ignore_above": 1024, - "type": "keyword" - }, - "service": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "span": { - "dynamic": "false", - "properties": { - "action": { - "ignore_above": 1024, - "type": "keyword" - }, - "db": { - "dynamic": "false", - "properties": { - "link": { - "ignore_above": 1024, - "type": "keyword" - }, - "rows_affected": { - "type": "long" - } - } - }, - "destination": { - "dynamic": "false", - "properties": { - "service": { - "dynamic": "false", - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "resource": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "duration": { - "properties": { - "us": { - "type": "long" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "message": { - "dynamic": "false", - "properties": { - "age": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "queue": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "self_time": { - "properties": { - "count": { - "type": "long" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - } - } - }, - "start": { - "properties": { - "us": { - "type": "long" - } - } - }, - "subtype": { - "ignore_above": 1024, - "type": "keyword" - }, - "sync": { - "type": "boolean" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "system": { - "properties": { - "cpu": { - "properties": { - "total": { - "properties": { - "norm": { - "properties": { - "pct": { - "scaling_factor": 1000, - "type": "scaled_float" - } - } - } - } - } - } - }, - "memory": { - "properties": { - "actual": { - "properties": { - "free": { - "type": "long" - } - } - }, - "total": { - "type": "long" - } - } - }, - "process": { - "properties": { - "cpu": { - "properties": { - "total": { - "properties": { - "norm": { - "properties": { - "pct": { - "scaling_factor": 1000, - "type": "scaled_float" - } - } - } - } - } - } - }, - "memory": { - "properties": { - "rss": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "size": { - "type": "long" - } - } - } - } - } - } - }, - "tags": { - "ignore_above": 1024, - "type": "keyword" - }, - "threat": { - "properties": { - "framework": { - "ignore_above": 1024, - "type": "keyword" - }, - "tactic": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "technique": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "timeseries": { - "properties": { - "instance": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "timestamp": { - "properties": { - "us": { - "type": "long" - } - } - }, - "tls": { - "properties": { - "cipher": { - "ignore_above": 1024, - "type": "keyword" - }, - "client": { - "properties": { - "certificate": { - "ignore_above": 1024, - "type": "keyword" - }, - "certificate_chain": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "issuer": { - "ignore_above": 1024, - "type": "keyword" - }, - "ja3": { - "ignore_above": 1024, - "type": "keyword" - }, - "not_after": { - "type": "date" - }, - "not_before": { - "type": "date" - }, - "server_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject": { - "ignore_above": 1024, - "type": "keyword" - }, - "supported_ciphers": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "curve": { - "ignore_above": 1024, - "type": "keyword" - }, - "established": { - "type": "boolean" - }, - "next_protocol": { - "ignore_above": 1024, - "type": "keyword" - }, - "resumed": { - "type": "boolean" - }, - "server": { - "properties": { - "certificate": { - "ignore_above": 1024, - "type": "keyword" - }, - "certificate_chain": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "issuer": { - "ignore_above": 1024, - "type": "keyword" - }, - "ja3s": { - "ignore_above": 1024, - "type": "keyword" - }, - "not_after": { - "type": "date" - }, - "not_before": { - "type": "date" - }, - "subject": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - }, - "version_protocol": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "trace": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "tracing": { - "properties": { - "trace": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "transaction": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "transaction": { - "dynamic": "false", - "properties": { - "breakdown": { - "properties": { - "count": { - "type": "long" - } - } - }, - "duration": { - "properties": { - "count": { - "type": "long" - }, - "histogram": { - "type": "histogram" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - }, - "us": { - "type": "long" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "marks": { - "dynamic": "true", - "properties": { - "*": { - "properties": { - "*": { - "dynamic": "true", - "type": "object" - } - } - } - } - }, - "message": { - "dynamic": "false", - "properties": { - "age": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "queue": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "result": { - "ignore_above": 1024, - "type": "keyword" - }, - "root": { - "type": "boolean" - }, - "sampled": { - "type": "boolean" - }, - "self_time": { - "properties": { - "count": { - "type": "long" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - } - } - }, - "span_count": { - "properties": { - "dropped": { - "type": "long" - } - } - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "url": { - "dynamic": "false", - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "extension": { - "ignore_above": 1024, - "type": "keyword" - }, - "fragment": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "password": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "port": { - "type": "long" - }, - "query": { - "ignore_above": 1024, - "type": "keyword" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "scheme": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "username": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "user": { - "dynamic": "false", - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "user_agent": { - "dynamic": "false", - "properties": { - "device": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "view spans": { - "ignore_above": 1024, - "type": "keyword" - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vulnerability": { - "properties": { - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "classification": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "enumeration": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "report_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "scanner": { - "properties": { - "vendor": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "score": { - "properties": { - "base": { - "type": "float" - }, - "environmental": { - "type": "float" - }, - "temporal": { - "type": "float" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "severity": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "settings": { - "index": { - "codec": "best_compression", - "lifecycle": { - "name": "apm-rollover-30-days", - "rollover_alias": "apm-8.0.0-span" - }, - "mapping": { - "total_fields": { - "limit": "2000" - } - }, - "number_of_replicas": "0", - "number_of_shards": "1", - "priority": "100", - "query": { - "default_field": [ - "message", - "tags", - "agent.ephemeral_id", - "agent.id", - "agent.name", - "agent.type", - "agent.version", - "as.organization.name", - "client.address", - "client.as.organization.name", - "client.domain", - "client.geo.city_name", - "client.geo.continent_name", - "client.geo.country_iso_code", - "client.geo.country_name", - "client.geo.name", - "client.geo.region_iso_code", - "client.geo.region_name", - "client.mac", - "client.registered_domain", - "client.top_level_domain", - "client.user.domain", - "client.user.email", - "client.user.full_name", - "client.user.group.domain", - "client.user.group.id", - "client.user.group.name", - "client.user.hash", - "client.user.id", - "client.user.name", - "cloud.account.id", - "cloud.availability_zone", - "cloud.instance.id", - "cloud.instance.name", - "cloud.machine.type", - "cloud.provider", - "cloud.region", - "container.id", - "container.image.name", - "container.image.tag", - "container.name", - "container.runtime", - "destination.address", - "destination.as.organization.name", - "destination.domain", - "destination.geo.city_name", - "destination.geo.continent_name", - "destination.geo.country_iso_code", - "destination.geo.country_name", - "destination.geo.name", - "destination.geo.region_iso_code", - "destination.geo.region_name", - "destination.mac", - "destination.registered_domain", - "destination.top_level_domain", - "destination.user.domain", - "destination.user.email", - "destination.user.full_name", - "destination.user.group.domain", - "destination.user.group.id", - "destination.user.group.name", - "destination.user.hash", - "destination.user.id", - "destination.user.name", - "dns.answers.class", - "dns.answers.data", - "dns.answers.name", - "dns.answers.type", - "dns.header_flags", - "dns.id", - "dns.op_code", - "dns.question.class", - "dns.question.name", - "dns.question.registered_domain", - "dns.question.subdomain", - "dns.question.top_level_domain", - "dns.question.type", - "dns.response_code", - "dns.type", - "ecs.version", - "error.code", - "error.id", - "error.message", - "error.stack_trace", - "error.type", - "event.action", - "event.category", - "event.code", - "event.dataset", - "event.hash", - "event.id", - "event.kind", - "event.module", - "event.original", - "event.outcome", - "event.provider", - "event.timezone", - "event.type", - "file.device", - "file.directory", - "file.extension", - "file.gid", - "file.group", - "file.hash.md5", - "file.hash.sha1", - "file.hash.sha256", - "file.hash.sha512", - "file.inode", - "file.mode", - "file.name", - "file.owner", - "file.path", - "file.target_path", - "file.type", - "file.uid", - "geo.city_name", - "geo.continent_name", - "geo.country_iso_code", - "geo.country_name", - "geo.name", - "geo.region_iso_code", - "geo.region_name", - "group.domain", - "group.id", - "group.name", - "hash.md5", - "hash.sha1", - "hash.sha256", - "hash.sha512", - "host.architecture", - "host.geo.city_name", - "host.geo.continent_name", - "host.geo.country_iso_code", - "host.geo.country_name", - "host.geo.name", - "host.geo.region_iso_code", - "host.geo.region_name", - "host.hostname", - "host.id", - "host.mac", - "host.name", - "host.os.family", - "host.os.full", - "host.os.kernel", - "host.os.name", - "host.os.platform", - "host.os.version", - "host.type", - "host.user.domain", - "host.user.email", - "host.user.full_name", - "host.user.group.domain", - "host.user.group.id", - "host.user.group.name", - "host.user.hash", - "host.user.id", - "host.user.name", - "http.request.body.content", - "http.request.method", - "http.request.referrer", - "http.response.body.content", - "http.version", - "log.level", - "log.logger", - "log.origin.file.name", - "log.origin.function", - "log.original", - "log.syslog.facility.name", - "log.syslog.severity.name", - "network.application", - "network.community_id", - "network.direction", - "network.iana_number", - "network.name", - "network.protocol", - "network.transport", - "network.type", - "observer.geo.city_name", - "observer.geo.continent_name", - "observer.geo.country_iso_code", - "observer.geo.country_name", - "observer.geo.name", - "observer.geo.region_iso_code", - "observer.geo.region_name", - "observer.hostname", - "observer.mac", - "observer.name", - "observer.os.family", - "observer.os.full", - "observer.os.kernel", - "observer.os.name", - "observer.os.platform", - "observer.os.version", - "observer.product", - "observer.serial_number", - "observer.type", - "observer.vendor", - "observer.version", - "organization.id", - "organization.name", - "os.family", - "os.full", - "os.kernel", - "os.name", - "os.platform", - "os.version", - "package.architecture", - "package.checksum", - "package.description", - "package.install_scope", - "package.license", - "package.name", - "package.path", - "package.version", - "process.args", - "text", - "process.executable", - "process.hash.md5", - "process.hash.sha1", - "process.hash.sha256", - "process.hash.sha512", - "process.name", - "text", - "text", - "text", - "text", - "text", - "process.thread.name", - "process.title", - "process.working_directory", - "server.address", - "server.as.organization.name", - "server.domain", - "server.geo.city_name", - "server.geo.continent_name", - "server.geo.country_iso_code", - "server.geo.country_name", - "server.geo.name", - "server.geo.region_iso_code", - "server.geo.region_name", - "server.mac", - "server.registered_domain", - "server.top_level_domain", - "server.user.domain", - "server.user.email", - "server.user.full_name", - "server.user.group.domain", - "server.user.group.id", - "server.user.group.name", - "server.user.hash", - "server.user.id", - "server.user.name", - "service.ephemeral_id", - "service.id", - "service.name", - "service.node.name", - "service.state", - "service.type", - "service.version", - "source.address", - "source.as.organization.name", - "source.domain", - "source.geo.city_name", - "source.geo.continent_name", - "source.geo.country_iso_code", - "source.geo.country_name", - "source.geo.name", - "source.geo.region_iso_code", - "source.geo.region_name", - "source.mac", - "source.registered_domain", - "source.top_level_domain", - "source.user.domain", - "source.user.email", - "source.user.full_name", - "source.user.group.domain", - "source.user.group.id", - "source.user.group.name", - "source.user.hash", - "source.user.id", - "source.user.name", - "threat.framework", - "threat.tactic.id", - "threat.tactic.name", - "threat.tactic.reference", - "threat.technique.id", - "threat.technique.name", - "threat.technique.reference", - "tracing.trace.id", - "tracing.transaction.id", - "url.domain", - "url.extension", - "url.fragment", - "url.full", - "url.original", - "url.password", - "url.path", - "url.query", - "url.registered_domain", - "url.scheme", - "url.top_level_domain", - "url.username", - "user.domain", - "user.email", - "user.full_name", - "user.group.domain", - "user.group.id", - "user.group.name", - "user.hash", - "user.id", - "user.name", - "user_agent.device.name", - "user_agent.name", - "text", - "user_agent.original", - "user_agent.os.family", - "user_agent.os.full", - "user_agent.os.kernel", - "user_agent.os.name", - "user_agent.os.platform", - "user_agent.os.version", - "user_agent.version", - "text", - "timeseries.instance", - "cloud.project.id", - "cloud.image.id", - "host.os.build", - "host.os.codename", - "kubernetes.pod.name", - "kubernetes.pod.uid", - "kubernetes.namespace", - "kubernetes.node.name", - "kubernetes.replicaset.name", - "kubernetes.deployment.name", - "kubernetes.statefulset.name", - "kubernetes.container.name", - "kubernetes.container.image", - "processor.name", - "processor.event", - "url.scheme", - "url.full", - "url.domain", - "url.path", - "url.query", - "url.fragment", - "http.version", - "http.request.method", - "http.request.referrer", - "service.name", - "service.version", - "service.environment", - "service.node.name", - "service.language.name", - "service.language.version", - "service.runtime.name", - "service.runtime.version", - "service.framework.name", - "service.framework.version", - "transaction.id", - "transaction.type", - "text", - "transaction.name", - "span.type", - "span.subtype", - "trace.id", - "parent.id", - "agent.name", - "agent.version", - "agent.ephemeral_id", - "container.id", - "kubernetes.namespace", - "kubernetes.node.name", - "kubernetes.pod.name", - "kubernetes.pod.uid", - "host.architecture", - "host.hostname", - "host.name", - "host.os.platform", - "process.args", - "process.title", - "observer.listening", - "observer.hostname", - "observer.version", - "observer.type", - "user.name", - "user.id", - "user.email", - "destination.address", - "text", - "user_agent.original", - "user_agent.name", - "user_agent.version", - "user_agent.device.name", - "user_agent.os.platform", - "user_agent.os.name", - "user_agent.os.full", - "user_agent.os.family", - "user_agent.os.version", - "user_agent.os.kernel", - "cloud.account.id", - "cloud.account.name", - "cloud.availability_zone", - "cloud.instance.id", - "cloud.instance.name", - "cloud.machine.type", - "cloud.project.id", - "cloud.project.name", - "cloud.provider", - "cloud.region", - "error.id", - "error.culprit", - "error.grouping_key", - "error.exception.code", - "error.exception.message", - "error.exception.module", - "error.exception.type", - "error.log.level", - "error.log.logger_name", - "error.log.message", - "error.log.param_message", - "profile.top.id", - "profile.top.function", - "profile.top.filename", - "profile.stack.id", - "profile.stack.function", - "profile.stack.filename", - "sourcemap.service.name", - "sourcemap.service.version", - "sourcemap.bundle_filepath", - "view spans", - "child.id", - "span.id", - "span.name", - "span.action", - "span.db.link", - "span.destination.service.type", - "span.destination.service.name", - "span.destination.service.resource", - "span.message.queue.name", - "transaction.result", - "transaction.message.queue.name", - "fields.*" - ] - }, - "refresh_interval": "1ms" - } - } - } -} - -{ - "type": "index", - "value": { - "aliases": { - "apm-8.0.0-transaction": { - "is_write_index": true - } - }, - "index": "apm-8.0.0-transaction-000001", - "mappings": { - "_meta": { - "beat": "apm", - "version": "8.0.0" - }, - "date_detection": false, - "dynamic_templates": [ - { - "labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "labels.*" - } - }, - { - "container.labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "container.labels.*" - } - }, - { - "dns.answers": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "dns.answers.*" - } - }, - { - "log.syslog": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "log.syslog.*" - } - }, - { - "network.inner": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "network.inner.*" - } - }, - { - "observer.egress": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "observer.egress.*" - } - }, - { - "observer.ingress": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "observer.ingress.*" - } - }, - { - "fields": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "fields.*" - } - }, - { - "docker.container.labels": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "docker.container.labels.*" - } - }, - { - "kubernetes.labels.*": { - "mapping": { - "type": "keyword" - }, - "path_match": "kubernetes.labels.*" - } - }, - { - "kubernetes.annotations.*": { - "mapping": { - "type": "keyword" - }, - "path_match": "kubernetes.annotations.*" - } - }, - { - "labels_string": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "labels.*" - } - }, - { - "labels_boolean": { - "mapping": { - "type": "boolean" - }, - "match_mapping_type": "boolean", - "path_match": "labels.*" - } - }, - { - "labels_*": { - "mapping": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "path_match": "labels.*" - } - }, - { - "transaction.marks": { - "mapping": { - "type": "keyword" - }, - "match_mapping_type": "string", - "path_match": "transaction.marks.*" - } - }, - { - "transaction.marks.*.*": { - "mapping": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "path_match": "transaction.marks.*.*" - } - }, - { - "strings_as_keyword": { - "mapping": { - "ignore_above": 1024, - "type": "keyword" - }, - "match_mapping_type": "string" - } - } - ], - "properties": { - "@timestamp": { - "type": "date" - }, - "agent": { - "dynamic": "false", - "properties": { - "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "hostname": { - "path": "agent.name", - "type": "alias" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "child": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "client": { - "dynamic": "false", - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "cloud": { - "properties": { - "account": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "availability_zone": { - "ignore_above": 1024, - "type": "keyword" - }, - "image": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "instance": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "machine": { - "dynamic": "false", - "properties": { - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "project": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "provider": { - "ignore_above": 1024, - "type": "keyword" - }, - "region": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "container": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "image": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "tag": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "labels": { - "type": "object" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "runtime": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "destination": { - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "dll": { - "properties": { - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "dns": { - "properties": { - "answers": { - "properties": { - "class": { - "ignore_above": 1024, - "type": "keyword" - }, - "data": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "ttl": { - "type": "long" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "header_flags": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "op_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "question": { - "properties": { - "class": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "subdomain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "resolved_ip": { - "type": "ip" - }, - "response_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "docker": { - "properties": { - "container": { - "properties": { - "labels": { - "type": "object" - } - } - } - } - }, - "ecs": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "error": { - "dynamic": "false", - "properties": { - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "culprit": { - "ignore_above": 1024, - "type": "keyword" - }, - "exception": { - "properties": { - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "handled": { - "type": "boolean" - }, - "message": { - "norms": false, - "type": "text" - }, - "module": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "grouping_key": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "log": { - "properties": { - "level": { - "ignore_above": 1024, - "type": "keyword" - }, - "logger_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "message": { - "norms": false, - "type": "text" - }, - "param_message": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "message": { - "norms": false, - "type": "text" - }, - "stack_trace": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "event": { - "properties": { - "action": { - "ignore_above": 1024, - "type": "keyword" - }, - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "code": { - "ignore_above": 1024, - "type": "keyword" - }, - "created": { - "type": "date" - }, - "dataset": { - "ignore_above": 1024, - "type": "keyword" - }, - "duration": { - "type": "long" - }, - "end": { - "type": "date" - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "ingested": { - "type": "date" - }, - "kind": { - "ignore_above": 1024, - "type": "keyword" - }, - "module": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "ignore_above": 1024, - "type": "keyword" - }, - "outcome": { - "ignore_above": 1024, - "type": "keyword" - }, - "provider": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "risk_score": { - "type": "float" - }, - "risk_score_norm": { - "type": "float" - }, - "sequence": { - "type": "long" - }, - "severity": { - "type": "long" - }, - "start": { - "type": "date" - }, - "timezone": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "url": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "experimental": { - "dynamic": "true", - "type": "object" - }, - "fields": { - "type": "object" - }, - "file": { - "properties": { - "accessed": { - "type": "date" - }, - "attributes": { - "ignore_above": 1024, - "type": "keyword" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "created": { - "type": "date" - }, - "ctime": { - "type": "date" - }, - "device": { - "ignore_above": 1024, - "type": "keyword" - }, - "directory": { - "ignore_above": 1024, - "type": "keyword" - }, - "drive_letter": { - "ignore_above": 1, - "type": "keyword" - }, - "extension": { - "ignore_above": 1024, - "type": "keyword" - }, - "gid": { - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "inode": { - "ignore_above": 1024, - "type": "keyword" - }, - "mime_type": { - "ignore_above": 1024, - "type": "keyword" - }, - "mode": { - "ignore_above": 1024, - "type": "keyword" - }, - "mtime": { - "type": "date" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "owner": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "size": { - "type": "long" - }, - "target_path": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "uid": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "host": { - "dynamic": "false", - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "containerized": { - "type": "boolean" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "build": { - "ignore_above": 1024, - "type": "keyword" - }, - "codename": { - "ignore_above": 1024, - "type": "keyword" - }, - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "http": { - "dynamic": "false", - "properties": { - "request": { - "properties": { - "body": { - "properties": { - "bytes": { - "type": "long" - }, - "content": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "bytes": { - "type": "long" - }, - "headers": { - "enabled": false, - "type": "object" - }, - "method": { - "ignore_above": 1024, - "type": "keyword" - }, - "referrer": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "response": { - "properties": { - "body": { - "properties": { - "bytes": { - "type": "long" - }, - "content": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "bytes": { - "type": "long" - }, - "finished": { - "type": "boolean" - }, - "headers": { - "enabled": false, - "type": "object" - }, - "status_code": { - "type": "long" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "kubernetes": { - "dynamic": "false", - "properties": { - "annotations": { - "properties": { - "*": { - "type": "object" - } - } - }, - "container": { - "properties": { - "image": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "deployment": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "labels": { - "properties": { - "*": { - "type": "object" - } - } - }, - "namespace": { - "ignore_above": 1024, - "type": "keyword" - }, - "node": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pod": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "uid": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "replicaset": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "statefulset": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "labels": { - "dynamic": "true", - "properties": { - "foo": { - "type": "keyword" - }, - "lorem": { - "type": "keyword" - }, - "multi-line": { - "type": "keyword" - }, - "this-is-a-very-long-tag-name-without-any-spaces": { - "type": "keyword" - } - } - }, - "log": { - "properties": { - "level": { - "ignore_above": 1024, - "type": "keyword" - }, - "logger": { - "ignore_above": 1024, - "type": "keyword" - }, - "origin": { - "properties": { - "file": { - "properties": { - "line": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "original": { - "ignore_above": 1024, - "type": "keyword" - }, - "syslog": { - "properties": { - "facility": { - "properties": { - "code": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "priority": { - "type": "long" - }, - "severity": { - "properties": { - "code": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - } - } - }, - "message": { - "norms": false, - "type": "text" - }, - "network": { - "properties": { - "application": { - "ignore_above": 1024, - "type": "keyword" - }, - "bytes": { - "type": "long" - }, - "community_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "direction": { - "ignore_above": 1024, - "type": "keyword" - }, - "forwarded_ip": { - "type": "ip" - }, - "iana_number": { - "ignore_above": 1024, - "type": "keyword" - }, - "inner": { - "properties": { - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "packets": { - "type": "long" - }, - "protocol": { - "ignore_above": 1024, - "type": "keyword" - }, - "transport": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "observer": { - "dynamic": "false", - "properties": { - "egress": { - "properties": { - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "zone": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hostname": { - "ignore_above": 1024, - "type": "keyword" - }, - "ingress": { - "properties": { - "interface": { - "properties": { - "alias": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "zone": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "listening": { - "ignore_above": 1024, - "type": "keyword" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - }, - "serial_number": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "vendor": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - }, - "version_major": { - "type": "byte" - } - } - }, - "organization": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "package": { - "properties": { - "architecture": { - "ignore_above": 1024, - "type": "keyword" - }, - "build_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "checksum": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "install_scope": { - "ignore_above": 1024, - "type": "keyword" - }, - "installed": { - "type": "date" - }, - "license": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "size": { - "type": "long" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "parent": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "process": { - "dynamic": "false", - "properties": { - "args": { - "ignore_above": 1024, - "type": "keyword" - }, - "args_count": { - "type": "long" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "command_line": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "entity_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "executable": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "exit_code": { - "type": "long" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "parent": { - "properties": { - "args": { - "ignore_above": 1024, - "type": "keyword" - }, - "args_count": { - "type": "long" - }, - "code_signature": { - "properties": { - "exists": { - "type": "boolean" - }, - "status": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "trusted": { - "type": "boolean" - }, - "valid": { - "type": "boolean" - } - } - }, - "command_line": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "entity_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "executable": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "exit_code": { - "type": "long" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha512": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "pgid": { - "type": "long" - }, - "pid": { - "type": "long" - }, - "ppid": { - "type": "long" - }, - "start": { - "type": "date" - }, - "thread": { - "properties": { - "id": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "title": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "working_directory": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pe": { - "properties": { - "company": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "file_version": { - "ignore_above": 1024, - "type": "keyword" - }, - "original_file_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "product": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "pgid": { - "type": "long" - }, - "pid": { - "type": "long" - }, - "ppid": { - "type": "long" - }, - "start": { - "type": "date" - }, - "thread": { - "properties": { - "id": { - "type": "long" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "title": { - "ignore_above": 1024, - "type": "keyword" - }, - "uptime": { - "type": "long" - }, - "working_directory": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "processor": { - "properties": { - "event": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "profile": { - "dynamic": "false", - "properties": { - "alloc_objects": { - "properties": { - "count": { - "type": "long" - } - } - }, - "alloc_space": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "cpu": { - "properties": { - "ns": { - "type": "long" - } - } - }, - "duration": { - "type": "long" - }, - "inuse_objects": { - "properties": { - "count": { - "type": "long" - } - } - }, - "inuse_space": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "samples": { - "properties": { - "count": { - "type": "long" - } - } - }, - "stack": { - "dynamic": "false", - "properties": { - "filename": { - "ignore_above": 1024, - "type": "keyword" - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "line": { - "type": "long" - } - } - }, - "top": { - "dynamic": "false", - "properties": { - "filename": { - "ignore_above": 1024, - "type": "keyword" - }, - "function": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "line": { - "type": "long" - } - } - } - } - }, - "registry": { - "properties": { - "data": { - "properties": { - "bytes": { - "ignore_above": 1024, - "type": "keyword" - }, - "strings": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hive": { - "ignore_above": 1024, - "type": "keyword" - }, - "key": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "value": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "related": { - "properties": { - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "ip": { - "type": "ip" - }, - "user": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "rule": { - "properties": { - "author": { - "ignore_above": 1024, - "type": "keyword" - }, - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "license": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "ruleset": { - "ignore_above": 1024, - "type": "keyword" - }, - "uuid": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "server": { - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "service": { - "dynamic": "false", - "properties": { - "environment": { - "ignore_above": 1024, - "type": "keyword" - }, - "ephemeral_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "framework": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "language": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "node": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "runtime": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "state": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "source": { - "dynamic": "false", - "properties": { - "address": { - "ignore_above": 1024, - "type": "keyword" - }, - "as": { - "properties": { - "number": { - "type": "long" - }, - "organization": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "bytes": { - "type": "long" - }, - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "geo": { - "properties": { - "city_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "continent_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "country_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "location": { - "type": "geo_point" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_iso_code": { - "ignore_above": 1024, - "type": "keyword" - }, - "region_name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "ip": { - "type": "ip" - }, - "mac": { - "ignore_above": 1024, - "type": "keyword" - }, - "nat": { - "properties": { - "ip": { - "type": "ip" - }, - "port": { - "type": "long" - } - } - }, - "packets": { - "type": "long" - }, - "port": { - "type": "long" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "user": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "sourcemap": { - "dynamic": "false", - "properties": { - "bundle_filepath": { - "ignore_above": 1024, - "type": "keyword" - }, - "service": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "span": { - "dynamic": "false", - "properties": { - "action": { - "ignore_above": 1024, - "type": "keyword" - }, - "db": { - "dynamic": "false", - "properties": { - "link": { - "ignore_above": 1024, - "type": "keyword" - }, - "rows_affected": { - "type": "long" - } - } - }, - "destination": { - "dynamic": "false", - "properties": { - "service": { - "dynamic": "false", - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "resource": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "duration": { - "properties": { - "us": { - "type": "long" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "message": { - "dynamic": "false", - "properties": { - "age": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "queue": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "self_time": { - "properties": { - "count": { - "type": "long" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - } - } - }, - "start": { - "properties": { - "us": { - "type": "long" - } - } - }, - "subtype": { - "ignore_above": 1024, - "type": "keyword" - }, - "sync": { - "type": "boolean" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "system": { - "properties": { - "cpu": { - "properties": { - "total": { - "properties": { - "norm": { - "properties": { - "pct": { - "scaling_factor": 1000, - "type": "scaled_float" - } - } - } - } - } - } - }, - "memory": { - "properties": { - "actual": { - "properties": { - "free": { - "type": "long" - } - } - }, - "total": { - "type": "long" - } - } - }, - "process": { - "properties": { - "cpu": { - "properties": { - "total": { - "properties": { - "norm": { - "properties": { - "pct": { - "scaling_factor": 1000, - "type": "scaled_float" - } - } - } - } - } - } - }, - "memory": { - "properties": { - "rss": { - "properties": { - "bytes": { - "type": "long" - } - } - }, - "size": { - "type": "long" - } - } - } - } - } - } - }, - "tags": { - "ignore_above": 1024, - "type": "keyword" - }, - "threat": { - "properties": { - "framework": { - "ignore_above": 1024, - "type": "keyword" - }, - "tactic": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "technique": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "timeseries": { - "properties": { - "instance": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "timestamp": { - "properties": { - "us": { - "type": "long" - } - } - }, - "tls": { - "properties": { - "cipher": { - "ignore_above": 1024, - "type": "keyword" - }, - "client": { - "properties": { - "certificate": { - "ignore_above": 1024, - "type": "keyword" - }, - "certificate_chain": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "issuer": { - "ignore_above": 1024, - "type": "keyword" - }, - "ja3": { - "ignore_above": 1024, - "type": "keyword" - }, - "not_after": { - "type": "date" - }, - "not_before": { - "type": "date" - }, - "server_name": { - "ignore_above": 1024, - "type": "keyword" - }, - "subject": { - "ignore_above": 1024, - "type": "keyword" - }, - "supported_ciphers": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "curve": { - "ignore_above": 1024, - "type": "keyword" - }, - "established": { - "type": "boolean" - }, - "next_protocol": { - "ignore_above": 1024, - "type": "keyword" - }, - "resumed": { - "type": "boolean" - }, - "server": { - "properties": { - "certificate": { - "ignore_above": 1024, - "type": "keyword" - }, - "certificate_chain": { - "ignore_above": 1024, - "type": "keyword" - }, - "hash": { - "properties": { - "md5": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha1": { - "ignore_above": 1024, - "type": "keyword" - }, - "sha256": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "issuer": { - "ignore_above": 1024, - "type": "keyword" - }, - "ja3s": { - "ignore_above": 1024, - "type": "keyword" - }, - "not_after": { - "type": "date" - }, - "not_before": { - "type": "date" - }, - "subject": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - }, - "version_protocol": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "trace": { - "dynamic": "false", - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "tracing": { - "properties": { - "trace": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "transaction": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "transaction": { - "dynamic": "false", - "properties": { - "breakdown": { - "properties": { - "count": { - "type": "long" - } - } - }, - "duration": { - "properties": { - "count": { - "type": "long" - }, - "histogram": { - "type": "histogram" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - }, - "us": { - "type": "long" - } - } - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "marks": { - "dynamic": "true", - "properties": { - "*": { - "properties": { - "*": { - "dynamic": "true", - "type": "object" - } - } - }, - "agent": { - "properties": { - "domComplete": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "domInteractive": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "firstContentfulPaint": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "largestContentfulPaint": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "timeToFirstByte": { - "scaling_factor": 1000000, - "type": "scaled_float" - } - } - }, - "navigationTiming": { - "properties": { - "connectEnd": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "connectStart": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "domComplete": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "domContentLoadedEventEnd": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "domContentLoadedEventStart": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "domInteractive": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "domLoading": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "domainLookupEnd": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "domainLookupStart": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "fetchStart": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "loadEventEnd": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "loadEventStart": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "requestStart": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "responseEnd": { - "scaling_factor": 1000000, - "type": "scaled_float" - }, - "responseStart": { - "scaling_factor": 1000000, - "type": "scaled_float" - } - } - } - } - }, - "message": { - "dynamic": "false", - "properties": { - "age": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "queue": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "result": { - "ignore_above": 1024, - "type": "keyword" - }, - "root": { - "type": "boolean" - }, - "sampled": { - "type": "boolean" - }, - "self_time": { - "properties": { - "count": { - "type": "long" - }, - "sum": { - "properties": { - "us": { - "type": "long" - } - } - } - } - }, - "span_count": { - "properties": { - "dropped": { - "type": "long" - } - } - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "url": { - "dynamic": "false", - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "extension": { - "ignore_above": 1024, - "type": "keyword" - }, - "fragment": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "password": { - "ignore_above": 1024, - "type": "keyword" - }, - "path": { - "ignore_above": 1024, - "type": "keyword" - }, - "port": { - "type": "long" - }, - "query": { - "ignore_above": 1024, - "type": "keyword" - }, - "registered_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "scheme": { - "ignore_above": 1024, - "type": "keyword" - }, - "top_level_domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "username": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "user": { - "dynamic": "false", - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "email": { - "ignore_above": 1024, - "type": "keyword" - }, - "full_name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "group": { - "properties": { - "domain": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "hash": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "user_agent": { - "dynamic": "false", - "properties": { - "device": { - "properties": { - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "original": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "os": { - "properties": { - "family": { - "ignore_above": 1024, - "type": "keyword" - }, - "full": { - "ignore_above": 1024, - "type": "keyword" - }, - "kernel": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - }, - "platform": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "view spans": { - "ignore_above": 1024, - "type": "keyword" - }, - "vlan": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "name": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "vulnerability": { - "properties": { - "category": { - "ignore_above": 1024, - "type": "keyword" - }, - "classification": { - "ignore_above": 1024, - "type": "keyword" - }, - "description": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - }, - "enumeration": { - "ignore_above": 1024, - "type": "keyword" - }, - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "reference": { - "ignore_above": 1024, - "type": "keyword" - }, - "report_id": { - "ignore_above": 1024, - "type": "keyword" - }, - "scanner": { - "properties": { - "vendor": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "score": { - "properties": { - "base": { - "type": "float" - }, - "environmental": { - "type": "float" - }, - "temporal": { - "type": "float" - }, - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "severity": { - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "settings": { - "index": { - "codec": "best_compression", - "lifecycle": { - "name": "apm-rollover-30-days", - "rollover_alias": "apm-8.0.0-transaction" - }, - "mapping": { - "total_fields": { - "limit": "2000" - } - }, - "number_of_replicas": "0", - "number_of_shards": "1", - "priority": "100", - "query": { - "default_field": [ - "message", - "tags", - "agent.ephemeral_id", - "agent.id", - "agent.name", - "agent.type", - "agent.version", - "as.organization.name", - "client.address", - "client.as.organization.name", - "client.domain", - "client.geo.city_name", - "client.geo.continent_name", - "client.geo.country_iso_code", - "client.geo.country_name", - "client.geo.name", - "client.geo.region_iso_code", - "client.geo.region_name", - "client.mac", - "client.registered_domain", - "client.top_level_domain", - "client.user.domain", - "client.user.email", - "client.user.full_name", - "client.user.group.domain", - "client.user.group.id", - "client.user.group.name", - "client.user.hash", - "client.user.id", - "client.user.name", - "cloud.account.id", - "cloud.availability_zone", - "cloud.instance.id", - "cloud.instance.name", - "cloud.machine.type", - "cloud.provider", - "cloud.region", - "container.id", - "container.image.name", - "container.image.tag", - "container.name", - "container.runtime", - "destination.address", - "destination.as.organization.name", - "destination.domain", - "destination.geo.city_name", - "destination.geo.continent_name", - "destination.geo.country_iso_code", - "destination.geo.country_name", - "destination.geo.name", - "destination.geo.region_iso_code", - "destination.geo.region_name", - "destination.mac", - "destination.registered_domain", - "destination.top_level_domain", - "destination.user.domain", - "destination.user.email", - "destination.user.full_name", - "destination.user.group.domain", - "destination.user.group.id", - "destination.user.group.name", - "destination.user.hash", - "destination.user.id", - "destination.user.name", - "dns.answers.class", - "dns.answers.data", - "dns.answers.name", - "dns.answers.type", - "dns.header_flags", - "dns.id", - "dns.op_code", - "dns.question.class", - "dns.question.name", - "dns.question.registered_domain", - "dns.question.subdomain", - "dns.question.top_level_domain", - "dns.question.type", - "dns.response_code", - "dns.type", - "ecs.version", - "error.code", - "error.id", - "error.message", - "error.stack_trace", - "error.type", - "event.action", - "event.category", - "event.code", - "event.dataset", - "event.hash", - "event.id", - "event.kind", - "event.module", - "event.original", - "event.outcome", - "event.provider", - "event.timezone", - "event.type", - "file.device", - "file.directory", - "file.extension", - "file.gid", - "file.group", - "file.hash.md5", - "file.hash.sha1", - "file.hash.sha256", - "file.hash.sha512", - "file.inode", - "file.mode", - "file.name", - "file.owner", - "file.path", - "file.target_path", - "file.type", - "file.uid", - "geo.city_name", - "geo.continent_name", - "geo.country_iso_code", - "geo.country_name", - "geo.name", - "geo.region_iso_code", - "geo.region_name", - "group.domain", - "group.id", - "group.name", - "hash.md5", - "hash.sha1", - "hash.sha256", - "hash.sha512", - "host.architecture", - "host.geo.city_name", - "host.geo.continent_name", - "host.geo.country_iso_code", - "host.geo.country_name", - "host.geo.name", - "host.geo.region_iso_code", - "host.geo.region_name", - "host.hostname", - "host.id", - "host.mac", - "host.name", - "host.os.family", - "host.os.full", - "host.os.kernel", - "host.os.name", - "host.os.platform", - "host.os.version", - "host.type", - "host.user.domain", - "host.user.email", - "host.user.full_name", - "host.user.group.domain", - "host.user.group.id", - "host.user.group.name", - "host.user.hash", - "host.user.id", - "host.user.name", - "http.request.body.content", - "http.request.method", - "http.request.referrer", - "http.response.body.content", - "http.version", - "log.level", - "log.logger", - "log.origin.file.name", - "log.origin.function", - "log.original", - "log.syslog.facility.name", - "log.syslog.severity.name", - "network.application", - "network.community_id", - "network.direction", - "network.iana_number", - "network.name", - "network.protocol", - "network.transport", - "network.type", - "observer.geo.city_name", - "observer.geo.continent_name", - "observer.geo.country_iso_code", - "observer.geo.country_name", - "observer.geo.name", - "observer.geo.region_iso_code", - "observer.geo.region_name", - "observer.hostname", - "observer.mac", - "observer.name", - "observer.os.family", - "observer.os.full", - "observer.os.kernel", - "observer.os.name", - "observer.os.platform", - "observer.os.version", - "observer.product", - "observer.serial_number", - "observer.type", - "observer.vendor", - "observer.version", - "organization.id", - "organization.name", - "os.family", - "os.full", - "os.kernel", - "os.name", - "os.platform", - "os.version", - "package.architecture", - "package.checksum", - "package.description", - "package.install_scope", - "package.license", - "package.name", - "package.path", - "package.version", - "process.args", - "text", - "process.executable", - "process.hash.md5", - "process.hash.sha1", - "process.hash.sha256", - "process.hash.sha512", - "process.name", - "text", - "text", - "text", - "text", - "text", - "process.thread.name", - "process.title", - "process.working_directory", - "server.address", - "server.as.organization.name", - "server.domain", - "server.geo.city_name", - "server.geo.continent_name", - "server.geo.country_iso_code", - "server.geo.country_name", - "server.geo.name", - "server.geo.region_iso_code", - "server.geo.region_name", - "server.mac", - "server.registered_domain", - "server.top_level_domain", - "server.user.domain", - "server.user.email", - "server.user.full_name", - "server.user.group.domain", - "server.user.group.id", - "server.user.group.name", - "server.user.hash", - "server.user.id", - "server.user.name", - "service.ephemeral_id", - "service.id", - "service.name", - "service.node.name", - "service.state", - "service.type", - "service.version", - "source.address", - "source.as.organization.name", - "source.domain", - "source.geo.city_name", - "source.geo.continent_name", - "source.geo.country_iso_code", - "source.geo.country_name", - "source.geo.name", - "source.geo.region_iso_code", - "source.geo.region_name", - "source.mac", - "source.registered_domain", - "source.top_level_domain", - "source.user.domain", - "source.user.email", - "source.user.full_name", - "source.user.group.domain", - "source.user.group.id", - "source.user.group.name", - "source.user.hash", - "source.user.id", - "source.user.name", - "threat.framework", - "threat.tactic.id", - "threat.tactic.name", - "threat.tactic.reference", - "threat.technique.id", - "threat.technique.name", - "threat.technique.reference", - "tracing.trace.id", - "tracing.transaction.id", - "url.domain", - "url.extension", - "url.fragment", - "url.full", - "url.original", - "url.password", - "url.path", - "url.query", - "url.registered_domain", - "url.scheme", - "url.top_level_domain", - "url.username", - "user.domain", - "user.email", - "user.full_name", - "user.group.domain", - "user.group.id", - "user.group.name", - "user.hash", - "user.id", - "user.name", - "user_agent.device.name", - "user_agent.name", - "text", - "user_agent.original", - "user_agent.os.family", - "user_agent.os.full", - "user_agent.os.kernel", - "user_agent.os.name", - "user_agent.os.platform", - "user_agent.os.version", - "user_agent.version", - "text", - "timeseries.instance", - "cloud.project.id", - "cloud.image.id", - "host.os.build", - "host.os.codename", - "kubernetes.pod.name", - "kubernetes.pod.uid", - "kubernetes.namespace", - "kubernetes.node.name", - "kubernetes.replicaset.name", - "kubernetes.deployment.name", - "kubernetes.statefulset.name", - "kubernetes.container.name", - "kubernetes.container.image", - "processor.name", - "processor.event", - "url.scheme", - "url.full", - "url.domain", - "url.path", - "url.query", - "url.fragment", - "http.version", - "http.request.method", - "http.request.referrer", - "service.name", - "service.version", - "service.environment", - "service.node.name", - "service.language.name", - "service.language.version", - "service.runtime.name", - "service.runtime.version", - "service.framework.name", - "service.framework.version", - "transaction.id", - "transaction.type", - "text", - "transaction.name", - "span.type", - "span.subtype", - "trace.id", - "parent.id", - "agent.name", - "agent.version", - "agent.ephemeral_id", - "container.id", - "kubernetes.namespace", - "kubernetes.node.name", - "kubernetes.pod.name", - "kubernetes.pod.uid", - "host.architecture", - "host.hostname", - "host.name", - "host.os.platform", - "process.args", - "process.title", - "observer.listening", - "observer.hostname", - "observer.version", - "observer.type", - "user.name", - "user.id", - "user.email", - "destination.address", - "text", - "user_agent.original", - "user_agent.name", - "user_agent.version", - "user_agent.device.name", - "user_agent.os.platform", - "user_agent.os.name", - "user_agent.os.full", - "user_agent.os.family", - "user_agent.os.version", - "user_agent.os.kernel", - "cloud.account.id", - "cloud.account.name", - "cloud.availability_zone", - "cloud.instance.id", - "cloud.instance.name", - "cloud.machine.type", - "cloud.project.id", - "cloud.project.name", - "cloud.provider", - "cloud.region", - "error.id", - "error.culprit", - "error.grouping_key", - "error.exception.code", - "error.exception.message", - "error.exception.module", - "error.exception.type", - "error.log.level", - "error.log.logger_name", - "error.log.message", - "error.log.param_message", - "profile.top.id", - "profile.top.function", - "profile.top.filename", - "profile.stack.id", - "profile.stack.function", - "profile.stack.filename", - "sourcemap.service.name", - "sourcemap.service.version", - "sourcemap.bundle_filepath", - "view spans", - "child.id", - "span.id", - "span.name", - "span.action", - "span.db.link", - "span.destination.service.type", - "span.destination.service.name", - "span.destination.service.resource", - "span.message.queue.name", - "transaction.result", - "transaction.message.queue.name", - "fields.*" - ] - }, - "refresh_interval": "1ms" - } - } - } -} \ No newline at end of file diff --git a/x-pack/test/case_api_integration/common/lib/utils.ts b/x-pack/test/case_api_integration/common/lib/utils.ts index fb6f4fce3c29..c23df53c4fee 100644 --- a/x-pack/test/case_api_integration/common/lib/utils.ts +++ b/x-pack/test/case_api_integration/common/lib/utils.ts @@ -66,7 +66,7 @@ export const getJiraConnector = () => ({ config: { apiUrl: 'http://some.non.existent.com', projectKey: 'pkey', - casesConfiguration: { + incidentConfiguration: { mapping: [ { source: 'title', @@ -85,6 +85,7 @@ export const getJiraConnector = () => ({ }, ], }, + isCaseOwned: true, }, }); diff --git a/x-pack/test/functional/apps/maps/index.js b/x-pack/test/functional/apps/maps/index.js index ef8b4ad4c0f1..03b75601ec2a 100644 --- a/x-pack/test/functional/apps/maps/index.js +++ b/x-pack/test/functional/apps/maps/index.js @@ -28,7 +28,7 @@ export default function ({ loadTestFile, getService }) { }); describe('', function () { - this.tags('ciGroup7'); + this.tags('ciGroup9'); loadTestFile(require.resolve('./documents_source')); loadTestFile(require.resolve('./blended_vector_layer')); loadTestFile(require.resolve('./vector_styling')); diff --git a/x-pack/test/functional/es_archives/endpoint/metadata/destination_index/data.json b/x-pack/test/functional/es_archives/endpoint/metadata/destination_index/data.json new file mode 100644 index 000000000000..b19e5e2cbf1d --- /dev/null +++ b/x-pack/test/functional/es_archives/endpoint/metadata/destination_index/data.json @@ -0,0 +1,223 @@ +{ + "type": "doc", + "value": { + "id": "M92ScEJT9M9QusfIi3hpEb0AAAAAAAAA", + "index": "metrics-endpoint.metadata_current-default", + "source": { + "HostDetails": { + "@timestamp": 1579881969541, + "Endpoint": { + "policy": { + "applied": { + "id": "00000000-0000-0000-0000-000000000000", + "name": "Default", + "status": "failure" + } + }, + "status": "enrolled" + }, + "agent": { + "id": "3838df35-a095-4af4-8fce-0b6d78793f2e", + "name": "Elastic Endpoint", + "version": "6.8.0" + }, + "elastic": { + "agent": { + "id": "023fa40c-411d-4188-a941-4147bfadd095" + } + }, + "event": { + "action": "endpoint_metadata", + "category": [ + "host" + ], + "created": 1579881969541, + "dataset": "endpoint.metadata", + "id": "32f5fda2-48e4-4fae-b89e-a18038294d16", + "ingested": "2020-09-09T18:25:15.853783Z", + "kind": "metric", + "module": "endpoint", + "type": [ + "info" + ] + }, + "host": { + "hostname": "rezzani-7.example.com", + "id": "fc0ff548-feba-41b6-8367-65e8790d0eaf", + "ip": [ + "10.101.149.26", + "2606:a000:ffc0:39:11ef:37b9:3371:578c" + ], + "mac": [ + "e2-6d-f9-0-46-2e" + ], + "name": "rezzani-7.example.com", + "os": { + "Ext": { + "variant": "Windows Pro" + }, + "family": "Windows", + "full": "Windows 10", + "name": "windows 10.0", + "platform": "Windows", + "version": "10.0" + } + } + }, + "agent": { + "id": "3838df35-a095-4af4-8fce-0b6d78793f2e" + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "OU3RgCJaNnR90byeDEHutp8AAAAAAAAA", + "index": "metrics-endpoint.metadata_current-default", + "source": { + "HostDetails": { + "@timestamp": 1579881969541, + "Endpoint": { + "policy": { + "applied": { + "id": "C2A9093E-E289-4C0A-AA44-8C32A414FA7A", + "name": "Default", + "status": "failure" + } + }, + "status": "enrolled" + }, + "agent": { + "id": "963b081e-60d1-482c-befd-a5815fa8290f", + "name": "Elastic Endpoint", + "version": "6.6.1" + }, + "elastic": { + "agent": { + "id": "11488bae-880b-4e7b-8d28-aac2aa9de816" + } + }, + "event": { + "action": "endpoint_metadata", + "category": [ + "host" + ], + "created": 1579881969541, + "dataset": "endpoint.metadata", + "id": "32f5fda2-48e4-4fae-b89e-a18038294d14", + "ingested": "2020-09-09T18:25:14.919526Z", + "kind": "metric", + "module": "endpoint", + "type": [ + "info" + ] + }, + "host": { + "architecture": "x86", + "hostname": "cadmann-4.example.com", + "id": "1fb3e58f-6ab0-4406-9d2a-91911207a712", + "ip": [ + "10.192.213.130", + "10.70.28.129" + ], + "mac": [ + "a9-71-6a-cc-93-85", + "f7-31-84-d3-21-68", + "2-95-12-39-ca-71" + ], + "name": "cadmann-4.example.com", + "os": { + "Ext": { + "variant": "Windows Pro" + }, + "family": "Windows", + "full": "Windows 10", + "name": "windows 10.0", + "platform": "Windows", + "version": "10.0" + } + } + }, + "agent": { + "id": "963b081e-60d1-482c-befd-a5815fa8290f" + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "YjqDCEuI6JmLeLOSyZx_NhMAAAAAAAAA", + "index": "metrics-endpoint.metadata_current-default", + "source": { + "HostDetails": { + "@timestamp": 1579881969541, + "Endpoint": { + "policy": { + "applied": { + "id": "C2A9093E-E289-4C0A-AA44-8C32A414FA7A", + "name": "Default", + "status": "success" + } + }, + "status": "enrolled" + }, + "agent": { + "id": "b3412d6f-b022-4448-8fee-21cc936ea86b", + "name": "Elastic Endpoint", + "version": "6.0.0" + }, + "elastic": { + "agent": { + "id": "92ac1ce0-e1f7-409e-8af6-f17e97b1fc71" + } + }, + "event": { + "action": "endpoint_metadata", + "category": [ + "host" + ], + "created": 1579881969541, + "dataset": "endpoint.metadata", + "id": "32f5fda2-48e4-4fae-b89e-a18038294d15", + "ingested": "2020-09-09T18:25:15.853404Z", + "kind": "metric", + "module": "endpoint", + "type": [ + "info" + ] + }, + "host": { + "architecture": "x86_64", + "hostname": "thurlow-9.example.com", + "id": "2f735e3d-be14-483b-9822-bad06e9045ca", + "ip": [ + "10.46.229.234" + ], + "mac": [ + "30-8c-45-55-69-b8", + "e5-36-7e-8f-a3-84", + "39-a1-37-20-18-74" + ], + "name": "thurlow-9.example.com", + "os": { + "Ext": { + "variant": "Windows Server" + }, + "family": "Windows", + "full": "Windows Server 2016", + "name": "windows 10.0", + "platform": "Windows", + "version": "10.0" + } + } + }, + "agent": { + "id": "b3412d6f-b022-4448-8fee-21cc936ea86b" + } + } + } +} diff --git a/x-pack/test/functional/page_objects/space_selector_page.ts b/x-pack/test/functional/page_objects/space_selector_page.ts index 90196c89170d..b272175ff2b2 100644 --- a/x-pack/test/functional/page_objects/space_selector_page.ts +++ b/x-pack/test/functional/page_objects/space_selector_page.ts @@ -50,6 +50,126 @@ export function SpaceSelectorPageProvider({ getService, getPageObjects }: FtrPro return await testSubjects.click('spacesNavSelector'); } + async clickManageSpaces() { + await testSubjects.click('manageSpaces'); + } + + async clickCreateSpace() { + await testSubjects.click('createSpace'); + } + + async clickEnterSpaceName() { + await testSubjects.click('addSpaceName'); + } + + async addSpaceName(spaceName: string) { + await testSubjects.setValue('addSpaceName', spaceName); + } + + async clickSpaceAcustomAvatar() { + await testSubjects.click('space-avatar-space_a'); + } + + async clickSpaceInitials() { + await testSubjects.click('spaceLetterInitial'); + } + + async addSpaceInitials(spaceInitials: string) { + await testSubjects.setValue('spaceLetterInitial', spaceInitials); + } + + async clickColorPicker() { + await testSubjects.click('colorPickerAnchor'); + } + + async setColorinPicker(hexValue: string) { + await testSubjects.setValue('colorPickerAnchor', hexValue); + } + + async clickShowFeatures() { + await testSubjects.click('show-hide-section-link'); + } + + async clickChangeAllPriv() { + await testSubjects.click('changeAllPrivilegesButton'); + } + + async clickSaveSpaceCreation() { + await testSubjects.click('save-space-button'); + } + + async clickSpaceEditButton(spaceName: string) { + await testSubjects.click(`${spaceName}-editSpace`); + } + + async clickGoToRolesPage() { + await testSubjects.click('rolesManagementPage'); + } + + async clickCancelSpaceCreation() { + await testSubjects.click('cancel-space-button'); + } + + async clickOnCustomizeURL() { + await testSubjects.click('CustomizeOrReset'); + } + + async clickOnSpaceURLDisplay() { + await testSubjects.click('spaceURLDisplay'); + } + + async setSpaceURL(spaceURL: string) { + await testSubjects.setValue('spaceURLDisplay', spaceURL); + } + + async clickFeaturesVisibilityButton() { + await testSubjects.click('changeAllFeatureVisibilityPopover'); + } + + async clickHideAllFeatures() { + await testSubjects.click('spc-toggle-all-features-hide'); + } + + async clickShowAllFeatures() { + await testSubjects.click('spc-toggle-all-features-show'); + } + + async toggleFeatureVisibility(featureName: string) { + await testSubjects.click(`feature-${featureName}-toggle`); + } + + async clickOnDescriptionOfSpace() { + await testSubjects.click('descriptionSpaceText'); + } + + async setOnDescriptionOfSpace(descriptionSpace: string) { + await testSubjects.setValue('descriptionSpaceText', descriptionSpace); + } + + async clickOnDeleteSpaceButton(spaceName: string) { + await testSubjects.click(`${spaceName}-deleteSpace`); + } + + async setSpaceNameTobeDeleted(spaceName: string) { + await testSubjects.setValue('deleteSpaceInput', spaceName); + } + + async cancelDeletingSpace() { + await testSubjects.click('confirmModalCancelButton'); + } + + async confirmDeletingSpace() { + await testSubjects.click('confirmModalConfirmButton'); + } + + async clickOnSpaceb() { + await testSubjects.click('space-avatar-space_b'); + } + + async goToSpecificSpace(spaceName: string) { + await testSubjects.click(`${spaceName}-gotoSpace`); + } + async clickSpaceAvatar(spaceId: string) { return await retry.try(async () => { log.info(`SpaceSelectorPage:clickSpaceAvatar(${spaceId})`); diff --git a/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts b/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts index ffa1d9fd46c7..e01e065867ac 100644 --- a/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts +++ b/x-pack/test/functional/services/ml/data_frame_analytics_creation.ts @@ -10,25 +10,9 @@ import { FtrProviderContext } from '../../ftr_provider_context'; import { MlCommonUI } from './common_ui'; import { MlApi } from './api'; import { - ClassificationAnalysis, - RegressionAnalysis, -} from '../../../../plugins/ml/common/types/data_frame_analytics'; - -enum ANALYSIS_CONFIG_TYPE { - OUTLIER_DETECTION = 'outlier_detection', - REGRESSION = 'regression', - CLASSIFICATION = 'classification', -} - -const isRegressionAnalysis = (arg: any): arg is RegressionAnalysis => { - const keys = Object.keys(arg); - return keys.length === 1 && keys[0] === ANALYSIS_CONFIG_TYPE.REGRESSION; -}; - -const isClassificationAnalysis = (arg: any): arg is ClassificationAnalysis => { - const keys = Object.keys(arg); - return keys.length === 1 && keys[0] === ANALYSIS_CONFIG_TYPE.CLASSIFICATION; -}; + isRegressionAnalysis, + isClassificationAnalysis, +} from '../../../../plugins/ml/common/util/analytics_utils'; export function MachineLearningDataFrameAnalyticsCreationProvider( { getService }: FtrProviderContext, diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts index 1579d041c9f5..4c97c8556d7d 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts @@ -361,7 +361,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // await first run to complete so we have an initial state await retry.try(async () => { - const { instances: alertInstances } = await alerting.alerts.getAlertStatus(alert.id); + const { instances: alertInstances } = await alerting.alerts.getAlertInstanceSummary( + alert.id + ); expect(Object.keys(alertInstances).length).to.eql(instances.length); }); }); @@ -373,10 +375,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify content await testSubjects.existOrFail('alertInstancesList'); - const status = await alerting.alerts.getAlertStatus(alert.id); + const summary = await alerting.alerts.getAlertInstanceSummary(alert.id); const dateOnAllInstancesFromApiResponse = mapValues( - status.instances, + summary.instances, (instance) => instance.activeStartDate ); @@ -570,7 +572,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // await first run to complete so we have an initial state await retry.try(async () => { - const { instances: alertInstances } = await alerting.alerts.getAlertStatus(alert.id); + const { instances: alertInstances } = await alerting.alerts.getAlertInstanceSummary( + alert.id + ); expect(Object.keys(alertInstances).length).to.eql(instances.length); }); @@ -591,7 +595,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify content await testSubjects.existOrFail('alertInstancesList'); - const { instances: alertInstances } = await alerting.alerts.getAlertStatus(alert.id); + const { instances: alertInstances } = await alerting.alerts.getAlertInstanceSummary( + alert.id + ); const items = await pageObjects.alertDetailsUI.getAlertInstancesList(); expect(items.length).to.eql(PAGE_SIZE); @@ -604,7 +610,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify content await testSubjects.existOrFail('alertInstancesList'); - const { instances: alertInstances } = await alerting.alerts.getAlertStatus(alert.id); + const { instances: alertInstances } = await alerting.alerts.getAlertInstanceSummary( + alert.id + ); await pageObjects.alertDetailsUI.clickPaginationNextPage(); diff --git a/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts b/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts index c6fbdecf77f1..942b352b4afd 100644 --- a/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts +++ b/x-pack/test/functional_with_es_ssl/services/alerting/alerts.ts @@ -8,7 +8,7 @@ import axios, { AxiosInstance } from 'axios'; import util from 'util'; import { ToolingLog } from '@kbn/dev-utils'; -export interface AlertStatus { +export interface AlertInstanceSummary { status: string; muted: boolean; enabled: boolean; @@ -156,10 +156,10 @@ export class Alerts { this.log.debug(`deleted alert ${alert.id}`); } - public async getAlertStatus(id: string): Promise { + public async getAlertInstanceSummary(id: string): Promise { this.log.debug(`getting alert ${id} state`); - const { data } = await this.axios.get(`/api/alerts/alert/${id}/status`); + const { data } = await this.axios.get(`/api/alerts/alert/${id}/_instance_summary`); return data; } diff --git a/x-pack/test/ingest_manager_api_integration/apis/epm/install_remove_assets.ts b/x-pack/test/ingest_manager_api_integration/apis/epm/install_remove_assets.ts index c7cfee565b2e..198c129b7482 100644 --- a/x-pack/test/ingest_manager_api_integration/apis/epm/install_remove_assets.ts +++ b/x-pack/test/ingest_manager_api_integration/apis/epm/install_remove_assets.ts @@ -84,6 +84,13 @@ export default function (providerContext: FtrProviderContext) { }); expect(resSettings.statusCode).equal(200); }); + it('should have installed the transform components', async function () { + const res = await es.transport.request({ + method: 'GET', + path: `/_transform/${logsTemplateName}-default-${pkgVersion}`, + }); + expect(res.statusCode).equal(200); + }); it('should have installed the kibana assets', async function () { const resIndexPatternLogs = await kibanaServer.savedObjects.get({ type: 'index-pattern', @@ -161,6 +168,10 @@ export default function (providerContext: FtrProviderContext) { id: 'metrics-all_assets.test_metrics', type: 'index_template', }, + { + id: 'logs-all_assets.test_logs-default-0.1.0', + type: 'transform', + }, ], es_index_patterns: { test_logs: 'logs-all_assets.test_logs-*', @@ -237,6 +248,18 @@ export default function (providerContext: FtrProviderContext) { ); expect(resPipeline2.statusCode).equal(404); }); + it('should have uninstalled the transforms', async function () { + const res = await es.transport.request( + { + method: 'GET', + path: `/_transform/${logsTemplateName}-default-${pkgVersion}`, + }, + { + ignore: [404], + } + ); + expect(res.statusCode).equal(404); + }); it('should have uninstalled the kibana assets', async function () { let resDashboard; try { diff --git a/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/elasticsearch/transform/default.json b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/elasticsearch/transform/default.json new file mode 100644 index 000000000000..27f75af131ee --- /dev/null +++ b/x-pack/test/ingest_manager_api_integration/apis/fixtures/test_packages/all_assets/0.1.0/dataset/test_logs/elasticsearch/transform/default.json @@ -0,0 +1,35 @@ +{ + "source": { + "index": "logs-all_assets.test_log-default*" + }, + "dest": { + "index": "logs-all_assets.test_log_current-default" + }, + "pivot": { + "group_by": { + "agent.id": { + "terms": { + "field": "agent.id" + } + } + }, + "aggregations": { + "HostDetails": { + "scripted_metric": { + "init_script": "state.timestamp_latest = 0L; state.last_doc=''", + "map_script": "def current_date = doc['@timestamp'].getValue().toInstant().toEpochMilli(); if (current_date \u003e state.timestamp_latest) {state.timestamp_latest = current_date;state.last_doc = new HashMap(params['_source']);}", + "combine_script": "return state", + "reduce_script": "def last_doc = '';def timestamp_latest = 0L; for (s in states) {if (s.timestamp_latest \u003e (timestamp_latest)) {timestamp_latest = s.timestamp_latest; last_doc = s.last_doc;}} return last_doc" + } + } + } + }, + "description": "collapse and update the latest document for each host", + "frequency": "1m", + "sync": { + "time": { + "field": "event.ingested", + "delay": "60s" + } + } +} diff --git a/x-pack/test/ingest_manager_api_integration/config.ts b/x-pack/test/ingest_manager_api_integration/config.ts index 08d5da148b51..94fbee0593d3 100644 --- a/x-pack/test/ingest_manager_api_integration/config.ts +++ b/x-pack/test/ingest_manager_api_integration/config.ts @@ -12,7 +12,7 @@ import { defineDockerServersConfig } from '@kbn/test'; // Docker image to use for Ingest Manager API integration tests. // This hash comes from the commit hash here: https://github.com/elastic/package-storage/commit export const dockerImage = - 'docker.elastic.co/package-registry/distribution:f6b01daec8cfe355101e366de9941d35a4c3763e'; + 'docker.elastic.co/package-registry/distribution:5e0e12ce1bc2cb0c2f67f2e07d11b9a6043bcf25'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { const xPackAPITestsConfig = await readConfigFile(require.resolve('../api_integration/config.ts')); diff --git a/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts b/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts index 1f4428e19853..459dc4739897 100644 --- a/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts +++ b/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts @@ -79,9 +79,9 @@ export default function ({ getService }: FtrProviderContext) { .expect(200); expect(user.username).to.eql(username); - expect(user.authentication_realm).to.eql({ name: 'reserved', type: 'reserved' }); expect(user.authentication_provider).to.eql('basic'); expect(user.authentication_type).to.eql('realm'); + // Do not assert on the `authentication_realm`, as the value differes for on-prem vs cloud }); describe('initiating SPNEGO', () => { diff --git a/x-pack/test/login_selector_api_integration/apis/login_selector.ts b/x-pack/test/login_selector_api_integration/apis/login_selector.ts index 7eb1f07d6750..44582355cf89 100644 --- a/x-pack/test/login_selector_api_integration/apis/login_selector.ts +++ b/x-pack/test/login_selector_api_integration/apis/login_selector.ts @@ -36,7 +36,7 @@ export default function ({ getService }: FtrProviderContext) { sessionCookie: Cookie, username: string, providerName: string, - authenticationRealm: { name: string; type: string }, + authenticationRealm: { name: string; type: string } | null, authenticationType: string ) { expect(sessionCookie.key).to.be('sid'); @@ -67,7 +67,9 @@ export default function ({ getService }: FtrProviderContext) { expect(apiResponse.body.username).to.be(username); expect(apiResponse.body.authentication_provider).to.be(providerName); - expect(apiResponse.body.authentication_realm).to.eql(authenticationRealm); + if (authenticationRealm) { + expect(apiResponse.body.authentication_realm).to.eql(authenticationRealm); + } expect(apiResponse.body.authentication_type).to.be(authenticationType); } @@ -228,16 +230,9 @@ export default function ({ getService }: FtrProviderContext) { const basicSessionCookie = request.cookie( basicAuthenticationResponse.headers['set-cookie'][0] )!; - await checkSessionCookie( - basicSessionCookie, - 'elastic', - 'basic1', - { - name: 'reserved', - type: 'reserved', - }, - 'realm' - ); + // Skip auth provider check since this comes from the reserved realm, + // which is not available when running on ESS + await checkSessionCookie(basicSessionCookie, 'elastic', 'basic1', null, 'realm'); const authenticationResponse = await supertest .post('/api/security/saml/callback') diff --git a/x-pack/test/oidc_api_integration/apis/authorization_code_flow/oidc_auth.ts b/x-pack/test/oidc_api_integration/apis/authorization_code_flow/oidc_auth.ts index 0a230ac84d99..c2335cf04504 100644 --- a/x-pack/test/oidc_api_integration/apis/authorization_code_flow/oidc_auth.ts +++ b/x-pack/test/oidc_api_integration/apis/authorization_code_flow/oidc_auth.ts @@ -43,9 +43,9 @@ export default function ({ getService }: FtrProviderContext) { .expect(200); expect(user.username).to.eql(username); - expect(user.authentication_realm).to.eql({ name: 'reserved', type: 'reserved' }); expect(user.authentication_provider).to.eql('basic'); expect(user.authentication_type).to.be('realm'); + // Do not assert on the `authentication_realm`, as the value differes for on-prem vs cloud }); describe('initiating handshake', () => { diff --git a/x-pack/test/pki_api_integration/apis/security/pki_auth.ts b/x-pack/test/pki_api_integration/apis/security/pki_auth.ts index 2f6b088ab719..0559e9e96fe3 100644 --- a/x-pack/test/pki_api_integration/apis/security/pki_auth.ts +++ b/x-pack/test/pki_api_integration/apis/security/pki_auth.ts @@ -93,8 +93,8 @@ export default function ({ getService }: FtrProviderContext) { .expect(200); expect(user.username).to.eql(username); - expect(user.authentication_realm).to.eql({ name: 'reserved', type: 'reserved' }); expect(user.authentication_provider).to.eql('basic'); + // Do not assert on the `authentication_realm`, as the value differes for on-prem vs cloud }); it('should properly set cookie and authenticate user', async () => { diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/spaces.ts b/x-pack/test/reporting_api_integration/reporting_and_security/spaces.ts index 6a68bd530cf6..9eafd0c31838 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/spaces.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/spaces.ts @@ -27,8 +27,7 @@ export default function ({ getService }: FtrProviderContext) { ); }; - // FLAKY: https://github.com/elastic/kibana/issues/76551 - describe.skip('Exports from Non-default Space', () => { + describe('Exports from Non-default Space', () => { before(async () => { await esArchiver.load('reporting/ecommerce'); await esArchiver.load('reporting/ecommerce_kibana_spaces'); // dashboard in non default space @@ -54,7 +53,8 @@ export default function ({ getService }: FtrProviderContext) { expect(reportCompleted).to.match(/^"order_date",/); }); - it('should complete a job of PNG export of a dashboard in non-default space', async () => { + // FLAKY: https://github.com/elastic/kibana/issues/76551 + it.skip('should complete a job of PNG export of a dashboard in non-default space', async () => { const downloadPath = await reportingAPI.postJob( `/s/non_default_space/api/reporting/generate/png?jobParams=%28browserTimezone%3AUTC%2Clayout%3A%28dimensions%3A%28height%3A512%2Cwidth%3A2402%29%2Cid%3Apng%29%2CobjectType%3Adashboard%2CrelativeUrl%3A%27%2Fs%2Fnon_default_space%2Fapp%2Fdashboards%23%2Fview%2F3c9ee360-e7ee-11ea-a730-d58e9ea7581b%3F_g%3D%28filters%3A%21%21%28%29%2CrefreshInterval%3A%28pause%3A%21%21t%2Cvalue%3A0%29%2Ctime%3A%28from%3A%21%272019-06-10T03%3A17%3A28.800Z%21%27%2Cto%3A%21%272019-07-14T19%3A25%3A06.385Z%21%27%29%29%26_a%3D%28description%3A%21%27%21%27%2Cfilters%3A%21%21%28%29%2CfullScreenMode%3A%21%21f%2Coptions%3A%28hidePanelTitles%3A%21%21f%2CuseMargins%3A%21%21t%29%2Cquery%3A%28language%3Akuery%2Cquery%3A%21%27%21%27%29%2CtimeRestore%3A%21%21t%2Ctitle%3A%21%27Ecom%2520Dashboard%2520Non%2520Default%2520Space%21%27%2CviewMode%3Aview%29%27%2Ctitle%3A%27Ecom%20Dashboard%20Non%20Default%20Space%27%29` ); @@ -64,7 +64,8 @@ export default function ({ getService }: FtrProviderContext) { expect(reportCompleted).to.not.be(null); }); - it('should complete a job of PDF export of a dashboard in non-default space', async () => { + // FLAKY: https://github.com/elastic/kibana/issues/76551 + it.skip('should complete a job of PDF export of a dashboard in non-default space', async () => { const downloadPath = await reportingAPI.postJob( `/s/non_default_space/api/reporting/generate/printablePdf?jobParams=%28browserTimezone%3AUTC%2Clayout%3A%28dimensions%3A%28height%3A512%2Cwidth%3A2402%29%2Cid%3Apreserve_layout%29%2CobjectType%3Adashboard%2CrelativeUrls%3A%21%28%27%2Fs%2Fnon_default_space%2Fapp%2Fdashboards%23%2Fview%2F3c9ee360-e7ee-11ea-a730-d58e9ea7581b%3F_g%3D%28filters%3A%21%21%28%29%2CrefreshInterval%3A%28pause%3A%21%21t%2Cvalue%3A0%29%2Ctime%3A%28from%3A%21%272019-06-10T03%3A17%3A28.800Z%21%27%2Cto%3A%21%272019-07-14T19%3A25%3A06.385Z%21%27%29%29%26_a%3D%28description%3A%21%27%21%27%2Cfilters%3A%21%21%28%29%2CfullScreenMode%3A%21%21f%2Coptions%3A%28hidePanelTitles%3A%21%21f%2CuseMargins%3A%21%21t%29%2Cquery%3A%28language%3Akuery%2Cquery%3A%21%27%21%27%29%2CtimeRestore%3A%21%21t%2Ctitle%3A%21%27Ecom%2520Dashboard%2520Non%2520Default%2520Space%21%27%2CviewMode%3Aview%29%27%29%2Ctitle%3A%27Ecom%20Dashboard%20Non%20Default%20Space%27%29` ); diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/usage.ts b/x-pack/test/reporting_api_integration/reporting_and_security/usage.ts index 49db8696c113..aaf4dd392641 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/usage.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/usage.ts @@ -21,8 +21,7 @@ export default function ({ getService }: FtrProviderContext) { const reportingAPI = getService('reportingAPI'); const usageAPI = getService('usageAPI'); - // FAILING: https://github.com/elastic/kibana/issues/76581 - describe.skip('Usage', () => { + describe('Usage', () => { before(async () => { await esArchiver.load(OSS_KIBANA_ARCHIVE_PATH); await esArchiver.load(OSS_DATA_ARCHIVE_PATH); @@ -116,7 +115,8 @@ export default function ({ getService }: FtrProviderContext) { }); }); - describe('from new jobs posted', () => { + // FAILING: https://github.com/elastic/kibana/issues/76581 + describe.skip('from new jobs posted', () => { it('should handle csv', async () => { await reportingAPI.expectAllJobsToFinishSuccessfully( await Promise.all([ diff --git a/x-pack/test/saml_api_integration/apis/security/saml_login.ts b/x-pack/test/saml_api_integration/apis/security/saml_login.ts index 501e1e5f2c20..2da7c92cd07b 100644 --- a/x-pack/test/saml_api_integration/apis/security/saml_login.ts +++ b/x-pack/test/saml_api_integration/apis/security/saml_login.ts @@ -93,9 +93,9 @@ export default function ({ getService }: FtrProviderContext) { .expect(200); expect(user.username).to.eql(username); - expect(user.authentication_realm).to.eql({ name: 'reserved', type: 'reserved' }); expect(user.authentication_provider).to.eql('basic'); expect(user.authentication_type).to.be('realm'); + // Do not assert on the `authentication_realm`, as the value differes for on-prem vs cloud }); describe('initiating handshake', () => { diff --git a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts index 81ffc5eea922..ed501b235a45 100644 --- a/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts +++ b/x-pack/test/saved_object_api_integration/security_and_spaces/apis/index.ts @@ -12,7 +12,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { const supertest = getService('supertest'); describe('saved objects security and spaces enabled', function () { - this.tags('ciGroup5'); + this.tags('ciGroup8'); before(async () => { await createUsersAndRoles(es, supertest); diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts index c9385bf9cebf..00b4b82f9d60 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/endpoint_list.ts @@ -6,7 +6,13 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { deleteMetadataStream } from '../../../security_solution_endpoint_api_int/apis/data_stream_helper'; + +import { + deleteMetadataCurrentStream, + deleteMetadataStream, + deleteAllDocsFromMetadataCurrentIndex, +} from '../../../security_solution_endpoint_api_int/apis/data_stream_helper'; + export default ({ getPageObjects, getService }: FtrProviderContext) => { const pageObjects = getPageObjects(['common', 'endpoint', 'header', 'endpointPageUtils']); const esArchiver = getService('esArchiver'); @@ -23,6 +29,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { 'Version', 'Last Active', ], + [ + 'rezzani-7.example.com', + 'Error', + 'Default', + 'Failure', + 'windows 10.0', + '10.101.149.26, 2606:a000:ffc0:39:11ef:37b9:3371:578c', + '6.8.0', + 'Jan 24, 2020 @ 16:06:09.541', + ], [ 'cadmann-4.example.com', 'Error', @@ -43,16 +59,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { '6.0.0', 'Jan 24, 2020 @ 16:06:09.541', ], - [ - 'rezzani-7.example.com', - 'Error', - 'Default', - 'Failure', - 'windows 10.0', - '10.101.149.26, 2606:a000:ffc0:39:11ef:37b9:3371:578c', - '6.8.0', - 'Jan 24, 2020 @ 16:06:09.541', - ], ]; describe('endpoint list', function () { @@ -61,10 +67,15 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('when initially navigating to page', () => { before(async () => { + await deleteMetadataStream(getService); + await deleteMetadataCurrentStream(getService); + await deleteAllDocsFromMetadataCurrentIndex(getService); await pageObjects.endpoint.navigateToEndpointList(); }); after(async () => { await deleteMetadataStream(getService); + await deleteMetadataCurrentStream(getService); + await deleteAllDocsFromMetadataCurrentIndex(getService); }); it('finds no data in list and prompts onboarding to add policy', async () => { @@ -72,8 +83,8 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('finds data after load and polling', async () => { - await esArchiver.load('endpoint/metadata/api_feature', { useCreate: true }); - await pageObjects.endpoint.waitForTableToHaveData('endpointListTable', 10000); + await esArchiver.load('endpoint/metadata/destination_index', { useCreate: true }); + await pageObjects.endpoint.waitForTableToHaveData('endpointListTable', 1100); const tableData = await pageObjects.endpointPageUtils.tableData('endpointListTable'); expect(tableData).to.eql(expectedData); }); @@ -81,11 +92,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('when there is data,', () => { before(async () => { - await esArchiver.load('endpoint/metadata/api_feature', { useCreate: true }); + await esArchiver.load('endpoint/metadata/destination_index', { useCreate: true }); await pageObjects.endpoint.navigateToEndpointList(); }); after(async () => { await deleteMetadataStream(getService); + await deleteMetadataCurrentStream(getService); + await deleteAllDocsFromMetadataCurrentIndex(getService); }); it('finds page title', async () => { @@ -202,10 +215,96 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - describe('when there is no data,', () => { + describe('displays the correct table data for the kql queries', () => { + before(async () => { + await esArchiver.load('endpoint/metadata/destination_index', { useCreate: true }); + await pageObjects.endpoint.navigateToEndpointList(); + }); + after(async () => { + await deleteMetadataStream(getService); + await deleteMetadataCurrentStream(getService); + await deleteAllDocsFromMetadataCurrentIndex(getService); + }); + it('for the kql query: na, table shows an empty list', async () => { + await testSubjects.setValue('adminSearchBar', 'na'); + await (await testSubjects.find('querySubmitButton')).click(); + const expectedDataFromQuery = [ + [ + 'Hostname', + 'Agent Status', + 'Integration', + 'Configuration Status', + 'Operating System', + 'IP Address', + 'Version', + 'Last Active', + ], + ['No items found'], + ]; + + await pageObjects.endpoint.waitForTableToNotHaveData('endpointListTable'); + const tableData = await pageObjects.endpointPageUtils.tableData('endpointListTable'); + expect(tableData).to.eql(expectedDataFromQuery); + }); + + it('for the kql query: HostDetails.Endpoint.policy.applied.id : "C2A9093E-E289-4C0A-AA44-8C32A414FA7A", table shows 2 items', async () => { + await testSubjects.setValue('adminSearchBar', ' '); + await (await testSubjects.find('querySubmitButton')).click(); + + const endpointListTableTotal = await testSubjects.getVisibleText('endpointListTableTotal'); + + await testSubjects.setValue( + 'adminSearchBar', + 'HostDetails.Endpoint.policy.applied.id : "C2A9093E-E289-4C0A-AA44-8C32A414FA7A" ' + ); + await (await testSubjects.find('querySubmitButton')).click(); + const expectedDataFromQuery = [ + [ + 'Hostname', + 'Agent Status', + 'Integration', + 'Configuration Status', + 'Operating System', + 'IP Address', + 'Version', + 'Last Active', + ], + [ + 'cadmann-4.example.com', + 'Error', + 'Default', + 'Failure', + 'windows 10.0', + '10.192.213.130, 10.70.28.129', + '6.6.1', + 'Jan 24, 2020 @ 16:06:09.541', + ], + [ + 'thurlow-9.example.com', + 'Error', + 'Default', + 'Success', + 'windows 10.0', + '10.46.229.234', + '6.0.0', + 'Jan 24, 2020 @ 16:06:09.541', + ], + ]; + + await pageObjects.endpoint.waitForVisibleTextToChange( + 'endpointListTableTotal', + endpointListTableTotal + ); + const tableData = await pageObjects.endpointPageUtils.tableData('endpointListTable'); + expect(tableData).to.eql(expectedDataFromQuery); + }); + }); + + describe.skip('when there is no data,', () => { before(async () => { // clear out the data and reload the page await deleteMetadataStream(getService); + await deleteMetadataCurrentStream(getService); await pageObjects.endpoint.navigateToEndpointList(); }); it('displays empty Policy Table page.', async () => { diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/data_stream_helper.ts b/x-pack/test/security_solution_endpoint_api_int/apis/data_stream_helper.ts index b16da16b3137..be25f26532d9 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/data_stream_helper.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/data_stream_helper.ts @@ -10,6 +10,7 @@ import { eventsIndexPattern, alertsIndexPattern, policyIndexPattern, + metadataCurrentIndexPattern, } from '../../../plugins/security_solution/common/endpoint/constants'; export async function deleteDataStream(getService: (serviceName: 'es') => Client, index: string) { @@ -25,10 +26,44 @@ export async function deleteDataStream(getService: (serviceName: 'es') => Client ); } +export async function deleteAllDocsFromIndex( + getService: (serviceName: 'es') => Client, + index: string +) { + const client = getService('es'); + await client.deleteByQuery( + { + body: { + query: { + match_all: {}, + }, + }, + index: `${index}`, + }, + { + ignore: [404], + } + ); +} + export async function deleteMetadataStream(getService: (serviceName: 'es') => Client) { await deleteDataStream(getService, metadataIndexPattern); } +export async function deleteMetadataCurrentStream(getService: (serviceName: 'es') => Client) { + await deleteDataStream(getService, metadataCurrentIndexPattern); +} + +export async function deleteAllDocsFromMetadataIndex(getService: (serviceName: 'es') => Client) { + await deleteAllDocsFromIndex(getService, metadataIndexPattern); +} + +export async function deleteAllDocsFromMetadataCurrentIndex( + getService: (serviceName: 'es') => Client +) { + await deleteAllDocsFromIndex(getService, metadataCurrentIndexPattern); +} + export async function deleteEventsStream(getService: (serviceName: 'es') => Client) { await deleteDataStream(getService, eventsIndexPattern); } diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts b/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts index 3afa9f397a2e..2286320ed7a8 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts @@ -5,7 +5,12 @@ */ import expect from '@kbn/expect/expect.js'; import { FtrProviderContext } from '../ftr_provider_context'; -import { deleteMetadataStream } from './data_stream_helper'; +import { + deleteAllDocsFromMetadataCurrentIndex, + deleteMetadataCurrentStream, + deleteAllDocsFromMetadataIndex, + deleteMetadataStream, +} from './data_stream_helper'; /** * The number of host documents in the es archive. @@ -15,12 +20,14 @@ const numberOfHostsInFixture = 3; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const supertest = getService('supertest'); + describe('test metadata api', () => { describe('POST /api/endpoint/metadata when index is empty', () => { it('metadata api should return empty result when index is empty', async () => { - // the endpoint uses data streams and es archiver does not support deleting them at the moment so we need - // to do it manually await deleteMetadataStream(getService); + await deleteAllDocsFromMetadataIndex(getService); + await deleteMetadataCurrentStream(getService); + await deleteAllDocsFromMetadataCurrentIndex(getService); const { body } = await supertest .post('/api/endpoint/metadata') .set('kbn-xsrf', 'xxx') @@ -34,12 +41,19 @@ export default function ({ getService }: FtrProviderContext) { }); describe('POST /api/endpoint/metadata when index is not empty', () => { - before( - async () => await esArchiver.load('endpoint/metadata/api_feature', { useCreate: true }) - ); + before(async () => { + await esArchiver.load('endpoint/metadata/api_feature', { useCreate: true }); + // wait for transform + await new Promise((r) => setTimeout(r, 120000)); + }); // the endpoint uses data streams and es archiver does not support deleting them at the moment so we need // to do it manually - after(async () => await deleteMetadataStream(getService)); + after(async () => { + await deleteMetadataStream(getService); + await deleteAllDocsFromMetadataIndex(getService); + await deleteMetadataCurrentStream(getService); + await deleteAllDocsFromMetadataCurrentIndex(getService); + }); it('metadata api should return one entry for each host with default paging', async () => { const { body } = await supertest .post('/api/endpoint/metadata') @@ -121,7 +135,7 @@ export default function ({ getService }: FtrProviderContext) { .set('kbn-xsrf', 'xxx') .send({ filters: { - kql: 'not host.ip:10.46.229.234', + kql: 'not HostDetails.host.ip:10.46.229.234', }, }) .expect(200); @@ -146,7 +160,7 @@ export default function ({ getService }: FtrProviderContext) { }, ], filters: { - kql: `not host.ip:${notIncludedIp}`, + kql: `not HostDetails.host.ip:${notIncludedIp}`, }, }) .expect(200); @@ -154,12 +168,14 @@ export default function ({ getService }: FtrProviderContext) { const resultIps: string[] = [].concat( ...body.hosts.map((hostInfo: Record) => hostInfo.metadata.host.ip) ); - expect(resultIps).to.eql([ - '10.192.213.130', - '10.70.28.129', - '10.101.149.26', - '2606:a000:ffc0:39:11ef:37b9:3371:578c', - ]); + expect(resultIps.sort()).to.eql( + [ + '10.192.213.130', + '10.70.28.129', + '10.101.149.26', + '2606:a000:ffc0:39:11ef:37b9:3371:578c', + ].sort() + ); expect(resultIps).not.include.eql(notIncludedIp); expect(body.hosts.length).to.eql(2); expect(body.request_page_size).to.eql(10); @@ -173,7 +189,7 @@ export default function ({ getService }: FtrProviderContext) { .set('kbn-xsrf', 'xxx') .send({ filters: { - kql: `host.os.Ext.variant:${variantValue}`, + kql: `HostDetails.host.os.Ext.variant:${variantValue}`, }, }) .expect(200); @@ -194,7 +210,7 @@ export default function ({ getService }: FtrProviderContext) { .set('kbn-xsrf', 'xxx') .send({ filters: { - kql: `host.ip:${targetEndpointIp}`, + kql: `HostDetails.host.ip:${targetEndpointIp}`, }, }) .expect(200); @@ -215,7 +231,7 @@ export default function ({ getService }: FtrProviderContext) { .set('kbn-xsrf', 'xxx') .send({ filters: { - kql: `not Endpoint.policy.applied.status:success`, + kql: `not HostDetails.Endpoint.policy.applied.status:success`, }, }) .expect(200); @@ -236,7 +252,7 @@ export default function ({ getService }: FtrProviderContext) { .set('kbn-xsrf', 'xxx') .send({ filters: { - kql: `elastic.agent.id:${targetElasticAgentId}`, + kql: `HostDetails.elastic.agent.id:${targetElasticAgentId}`, }, }) .expect(200); diff --git a/x-pack/test/ui_capabilities/security_only/tests/nav_links.ts b/x-pack/test/ui_capabilities/security_only/tests/nav_links.ts index d7a0dfa1cf80..091bbccd6f87 100644 --- a/x-pack/test/ui_capabilities/security_only/tests/nav_links.ts +++ b/x-pack/test/ui_capabilities/security_only/tests/nav_links.ts @@ -49,7 +49,13 @@ export default function navLinksTests({ getService }: FtrProviderContext) { expect(uiCapabilities.success).to.be(true); expect(uiCapabilities.value).to.have.property('navLinks'); expect(uiCapabilities.value!.navLinks).to.eql( - navLinksBuilder.except('ml', 'monitoring', 'appSearch', 'workplaceSearch') + navLinksBuilder.except( + 'ml', + 'monitoring', + 'enterpriseSearch', + 'appSearch', + 'workplaceSearch' + ) ); break; case 'foo_all': diff --git a/yarn.lock b/yarn.lock index 95066c9fa8cd..105c5e3cba5a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1144,10 +1144,10 @@ dependencies: "@elastic/apm-rum-core" "^5.6.0" -"@elastic/charts@21.0.1": - version "21.0.1" - resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-21.0.1.tgz#1e8be5303d0c7d53d7ccfcfa121ef68164ae200f" - integrity sha512-KMJE2JNwoy021Rvhgu1wiga0FVCa0u4NlFVUSR+h+G010KLarc+c9yUKBTG8v/nZ6ijBtuOLCjjU9OCWXYfxvA== +"@elastic/charts@21.1.2": + version "21.1.2" + resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-21.1.2.tgz#da7e9c1025bf730a738b6ac6d7024d97dd2b5aa2" + integrity sha512-Uri+Xolgii7/mRSarfXTfA6X2JC76ILIxTPO8RlYdI44gzprJfUO7Aw5s8vVQke3x6Cu39a+9B0s6TY4GAaApQ== dependencies: "@popperjs/core" "^2.4.0" chroma-js "^2.1.0" @@ -1168,9 +1168,6 @@ ts-debounce "^1.0.0" utility-types "^3.10.0" uuid "^3.3.2" - optionalDependencies: - redux-immutable-state-invariant "^2.1.0" - redux-logger "^3.0.6" "@elastic/elasticsearch@7.9.0-rc.1": version "7.9.0-rc.1" @@ -10394,11 +10391,6 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= -deep-diff@^0.3.5: - version "0.3.8" - resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-0.3.8.tgz#c01de63efb0eec9798801d40c7e0dae25b582c84" - integrity sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ= - deep-eql@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" @@ -12295,15 +12287,10 @@ eventemitter2@~0.4.13: resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab" integrity sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas= -eventemitter3@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" - integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA== - eventemitter3@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" - integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== events@^1.0.2: version "1.1.1" @@ -15524,11 +15511,11 @@ http-proxy-middleware@0.19.1: micromatch "^3.1.10" http-proxy@^1.17.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" - integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g== + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== dependencies: - eventemitter3 "^3.0.0" + eventemitter3 "^4.0.0" follow-redirects "^1.0.0" requires-port "^1.0.0" @@ -18207,10 +18194,10 @@ kdbush@^3.0.0: resolved "https://registry.yarnpkg.com/kdbush/-/kdbush-3.0.0.tgz#f8484794d47004cc2d85ed3a79353dbe0abc2bf0" integrity sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew== -kea@2.2.0-rc.4: - version "2.2.0-rc.4" - resolved "https://registry.yarnpkg.com/kea/-/kea-2.2.0-rc.4.tgz#cc0376950530a6751f73387c4b25a39efa1faa77" - integrity sha512-pYuwaCiJkBvHZShi8kqhk8dC4DjeELdK51Lw7Pn0tNdJgZJDF6COhsUiF/yrh9d7woNYDxKfuxH+QWZFfo8PkA== +kea@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/kea/-/kea-2.2.0.tgz#1ba4a174a53880cca8002a67cf62b19b30d09702" + integrity sha512-IzgTC6SC89wTLfiBMPlduG4r4YanxONYK4werz8RMZxPvcYw4XEEK8xQJguwVYtLCEGm4x5YiLCubGqGfRcbEw== kew@~0.1.7: version "0.1.7" @@ -24455,21 +24442,6 @@ redux-devtools-extension@^2.13.8: resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz#37b982688626e5e4993ff87220c9bbb7cd2d96e1" integrity sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg== -redux-immutable-state-invariant@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/redux-immutable-state-invariant/-/redux-immutable-state-invariant-2.1.0.tgz#308fd3cc7415a0e7f11f51ec997b6379c7055ce1" - integrity sha512-3czbDKs35FwiBRsx/3KabUk5zSOoTXC+cgVofGkpBNv3jQcqIe5JrHcF5AmVt7B/4hyJ8MijBIpCJ8cife6yJg== - dependencies: - invariant "^2.1.0" - json-stringify-safe "^5.0.1" - -redux-logger@^3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/redux-logger/-/redux-logger-3.0.6.tgz#f7555966f3098f3c88604c449cf0baf5778274bf" - integrity sha1-91VZZvMJjzyIYExEnPC69XeCdL8= - dependencies: - deep-diff "^0.3.5" - redux-observable@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/redux-observable/-/redux-observable-1.2.0.tgz#ff51b6c6be2598e9b5e89fc36639186bb0e669c7"