Merge branch 'master' into reporting/test-better

This commit is contained in:
Timothy Sullivan 2020-04-09 14:28:45 -07:00
commit 206fd14b77
472 changed files with 9812 additions and 4619 deletions

3
.github/CODEOWNERS vendored
View file

@ -202,7 +202,8 @@
# Endpoint
/x-pack/plugins/endpoint/ @elastic/endpoint-app-team
/x-pack/test/api_integration/apis/endpoint/ @elastic/endpoint-app-team
/x-pack/test/functional/apps/endpoint/ @elastic/endpoint-app-team
/x-pack/test/functional_endpoint/ @elastic/endpoint-app-team
/x-pack/test/functional_endpoint_ingest_failure/ @elastic/endpoint-app-team
/x-pack/test/functional/es_archives/endpoint/ @elastic/endpoint-app-team
# SIEM

View file

@ -24,6 +24,7 @@
"src/legacy/core_plugins/management",
"src/plugins/management"
],
"indexPatternManagement": "src/plugins/index_pattern_management",
"advancedSettings": "src/plugins/advanced_settings",
"kibana_legacy": "src/plugins/kibana_legacy",
"kibana_react": "src/legacy/core_plugins/kibana_react",

View file

@ -0,0 +1,97 @@
[role="xpack"]
[[apm-alerts]]
=== Create an alert
beta::[]
The APM app is integrated with Kibana's {kibana-ref}/alerting-getting-started.html[alerting and actions] feature.
It provides a set of built-in **actions** and APM specific threshold **alerts** for you to use,
and allows all alerts to be centrally managed from <<management,Kibana Management>>.
[role="screenshot"]
image::apm/images/apm-alert.png[Create an alert in the APM app]
There are two different types of threshold alerts: transaction duration, and error rate.
Below, we'll create one of each.
[float]
[[apm-create-transaction-alert]]
=== Create a transaction duration alert
This guide creates an alert for the `opbeans-java` service based on the following criteria:
* Transaction type: `transaction.type:request`
* Average request is above `1500ms` for the last 5 minutes
* Check every 10 minutes, and repeat the alert every 30 minutes
* Send the alert via Slack
From the APM app, navigate to the `opbeans-java` service and select
**Alerts** > **Create threshold alert** > **Transaction duration**.
The name of your alert will automatically be set as `Transaction duration | opbeans-java`,
and the alert will be tagged with `apm` and `service.name:opbeans-java`.
Feel free to edit either of these defaults.
Based on the alert criteria, define the following alert details:
* **Check every** - `10 minutes`
* **Notify every** - `30 minutes`
* **TYPE** - `request`
* **WHEN** - `avg`
* **IS ABOVE** - `1500ms`
* **FOR THE LAST** - `5 minutes`
Select an action type.
Multiple action types can be selected, but in this example we want to post to a slack channel.
Select **Slack** > **Create a connector**.
Enter a name for the connector,
and paste the webhook URL.
See Slack's webhook documentation if you need to create one.
Select **Save**. The alert has been created and is now active!
[float]
[[apm-create-error-alert]]
=== Create an error rate alert
This guide creates an alert for the `opbeans-python` service based on the following criteria:
* Error rate is above 25 for the last minute
* Check every 1 minute, and repeat the alert every 10 minutes
* Send the alert via email to the `opbeans-python` team
From the APM app, navigate to the `opbeans-python` service and select
**Alerts** > **Create threshold alert** > **Error rate**.
The name of your alert will automatically be set as `Error rate | opbeans-python`,
and the alert will be tagged with `apm` and `service.name:opbeans-python`.
Feel free to edit either of these defaults.
Based on the alert criteria, define the following alert details:
* **Check every** - `1 minute`
* **Notify every** - `10 minutes`
* **IS ABOVE** - `25 errors`
* **FOR THE LAST** - `1 minute`
Select the **Email** action type and click **Create a connector**.
Fill out the required details: sender, host, port, etc., and click **save**.
Select **Save**. The alert has been created and is now active!
[float]
[[apm-alert-manage]]
=== Manage alerts and actions
From the APM app, select **Alerts** > **View active alerts** to be taken to the Kibana alerts and actions management page.
From this page, you can create, edit, disable, mute, and delete alerts, and create, edit, and disable connectors.
[float]
[[apm-alert-more-info]]
=== More information
See {kibana-ref}/alerting-getting-started.html[alerting and actions] for more information.
NOTE: If you are using an **on-premise** Elastic Stack deployment with security,
TLS must be configured for communication between Elasticsearch and Kibana.
More information is in the alerting {kibana-ref}/alerting-getting-started.html#alerting-setup-prerequisites[prerequisites].

Binary file not shown.

After

Width:  |  Height:  |  Size: 643 KiB

View file

@ -34,4 +34,4 @@ which indicates the next transaction in the trace.
These transactions can be expanded and viewed in detail by clicking on them.
After exploring these traces,
you can return to the full trace by clicking *View full trace* in the upper right hand corner of the page.
you can return to the full trace by clicking *View full trace*.

View file

@ -105,6 +105,7 @@ image::apm/images/apm-transaction-duration-dist.png[Example view of transactions
This graph shows a typical distribution, and indicates most of our requests were served quickly - awesome!
It's the requests on the right, the ones taking longer than average, that we probably want to focus on.
When you select one of these buckets,
you're presented with up to ten trace samples.
Each sample has a span timeline waterfall that shows what a typical request in that bucket was doing.

View file

@ -15,6 +15,7 @@ APM is available via the navigation sidebar in {Kib}.
* <<spans>>
* <<errors>>
* <<metrics>>
* <<apm-alerts>>
* <<machine-learning-integration>>
* <<agent-configuration>>
* <<advanced-queries>>
@ -37,6 +38,8 @@ include::errors.asciidoc[]
include::metrics.asciidoc[]
include::apm-alerts.asciidoc[]
include::agent-configuration.asciidoc[]
include::custom-links.asciidoc[]

View file

@ -76,7 +76,7 @@ After you've added the workpad to your website, you can change the autoplay and
To change the autoplay settings:
. In the lower right corner of the shareable workpad, click the settings icon.
. Click the settings icon.
. Click *Auto Play*, then change the settings.
+
@ -85,7 +85,7 @@ image::images/canvas_share_autoplay_480.gif[Autoplay settings]
To change the toolbar settings:
. In the lower right corner, click the settings icon.
. Click the settings icon.
. Click *Toolbar*, then change the settings.
+

View file

@ -18,7 +18,7 @@ Your first step to working with Canvas is to create a workpad.
. Click *Create workpad*.
. To add a *Name* for your workpad, use the editor on the right. For example, `My Canvas Workpad`.
. To add a *Name* for your workpad, use the editor. For example, `My Canvas Workpad`.
[float]
=== Customize your workpad with images
@ -29,7 +29,7 @@ To customize your workpad to look the way you want, add your own images.
+
The default Elastic logo image appears on your page.
. To replace the Elastic logo with your own image, select the image, then use the editor on the right.
. To replace the Elastic logo with your own image, select the image, then use the editor.
. To move the image, click and drag it to your preferred location.
@ -73,7 +73,7 @@ You'll notice that the error is gone, but the number could use some formatting.
. To format the number, use the Canvas expression language.
.. In the lower right corner, click *Expression editor*.
.. Click *Expression editor*.
+
You're now looking at the raw data syntax that Canvas uses to display the element.

View file

@ -124,7 +124,7 @@ Organize your ideas onto separate pages by adding more pages.
. Click *Page 1*, then click *+*.
. On the *Page* editor panel on the right, select the page transition from the *Transition* dropdown.
. On the *Page* editor panel, select the page transition from the *Transition* dropdown.
+
[role="screenshot"]
image::images/canvas-add-pages.gif[Add pages]

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

View file

@ -0,0 +1,17 @@
[role="xpack"]
[[painlesslab]]
== Painless Lab
beta::[]
The Painless Lab is an interactive code editor that lets you test and
debug {ref}/modules-scripting-painless.html[Painless scripts] in real-time.
You can use the Painless scripting
language to create <<scripted-fields, {kib} scripted fields>>,
process {ref}/docs-reindex.html[reindexed data], define complex
<<watcher-create-advanced-watch, Watcher conditions>>,
and work with data in other contexts.
To get started, go to *Dev Tools > Painless Lab*.
image::dev-tools/painlesslab/images/painless-lab.png[Painless Lab]

View file

@ -23,6 +23,7 @@ export interface CoreSetup<TPluginsStart extends object = object, TStart = unkno
| [http](./kibana-plugin-core-server.coresetup.http.md) | <code>HttpServiceSetup</code> | [HttpServiceSetup](./kibana-plugin-core-server.httpservicesetup.md) |
| [metrics](./kibana-plugin-core-server.coresetup.metrics.md) | <code>MetricsServiceSetup</code> | [MetricsServiceSetup](./kibana-plugin-core-server.metricsservicesetup.md) |
| [savedObjects](./kibana-plugin-core-server.coresetup.savedobjects.md) | <code>SavedObjectsServiceSetup</code> | [SavedObjectsServiceSetup](./kibana-plugin-core-server.savedobjectsservicesetup.md) |
| [status](./kibana-plugin-core-server.coresetup.status.md) | <code>StatusServiceSetup</code> | [StatusServiceSetup](./kibana-plugin-core-server.statusservicesetup.md) |
| [uiSettings](./kibana-plugin-core-server.coresetup.uisettings.md) | <code>UiSettingsServiceSetup</code> | [UiSettingsServiceSetup](./kibana-plugin-core-server.uisettingsservicesetup.md) |
| [uuid](./kibana-plugin-core-server.coresetup.uuid.md) | <code>UuidServiceSetup</code> | [UuidServiceSetup](./kibana-plugin-core-server.uuidservicesetup.md) |

View file

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [CoreSetup](./kibana-plugin-core-server.coresetup.md) &gt; [status](./kibana-plugin-core-server.coresetup.status.md)
## CoreSetup.status property
[StatusServiceSetup](./kibana-plugin-core-server.statusservicesetup.md)
<b>Signature:</b>
```typescript
status: StatusServiceSetup;
```

View file

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [CoreStatus](./kibana-plugin-core-server.corestatus.md) &gt; [elasticsearch](./kibana-plugin-core-server.corestatus.elasticsearch.md)
## CoreStatus.elasticsearch property
<b>Signature:</b>
```typescript
elasticsearch: ServiceStatus;
```

View file

@ -0,0 +1,21 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [CoreStatus](./kibana-plugin-core-server.corestatus.md)
## CoreStatus interface
Status of core services.
<b>Signature:</b>
```typescript
export interface CoreStatus
```
## Properties
| Property | Type | Description |
| --- | --- | --- |
| [elasticsearch](./kibana-plugin-core-server.corestatus.elasticsearch.md) | <code>ServiceStatus</code> | |
| [savedObjects](./kibana-plugin-core-server.corestatus.savedobjects.md) | <code>ServiceStatus</code> | |

View file

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [CoreStatus](./kibana-plugin-core-server.corestatus.md) &gt; [savedObjects](./kibana-plugin-core-server.corestatus.savedobjects.md)
## CoreStatus.savedObjects property
<b>Signature:</b>
```typescript
savedObjects: ServiceStatus;
```

View file

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [ElasticsearchStatusMeta](./kibana-plugin-core-server.elasticsearchstatusmeta.md) &gt; [incompatibleNodes](./kibana-plugin-core-server.elasticsearchstatusmeta.incompatiblenodes.md)
## ElasticsearchStatusMeta.incompatibleNodes property
<b>Signature:</b>
```typescript
incompatibleNodes: NodesVersionCompatibility['incompatibleNodes'];
```

View file

@ -0,0 +1,20 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [ElasticsearchStatusMeta](./kibana-plugin-core-server.elasticsearchstatusmeta.md)
## ElasticsearchStatusMeta interface
<b>Signature:</b>
```typescript
export interface ElasticsearchStatusMeta
```
## Properties
| Property | Type | Description |
| --- | --- | --- |
| [incompatibleNodes](./kibana-plugin-core-server.elasticsearchstatusmeta.incompatiblenodes.md) | <code>NodesVersionCompatibility['incompatibleNodes']</code> | |
| [warningNodes](./kibana-plugin-core-server.elasticsearchstatusmeta.warningnodes.md) | <code>NodesVersionCompatibility['warningNodes']</code> | |

View file

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [ElasticsearchStatusMeta](./kibana-plugin-core-server.elasticsearchstatusmeta.md) &gt; [warningNodes](./kibana-plugin-core-server.elasticsearchstatusmeta.warningnodes.md)
## ElasticsearchStatusMeta.warningNodes property
<b>Signature:</b>
```typescript
warningNodes: NodesVersionCompatibility['warningNodes'];
```

View file

@ -66,6 +66,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
| [ContextSetup](./kibana-plugin-core-server.contextsetup.md) | An object that handles registration of context providers and configuring handlers with context. |
| [CoreSetup](./kibana-plugin-core-server.coresetup.md) | Context passed to the plugins <code>setup</code> method. |
| [CoreStart](./kibana-plugin-core-server.corestart.md) | Context passed to the plugins <code>start</code> method. |
| [CoreStatus](./kibana-plugin-core-server.corestatus.md) | Status of core services. |
| [CustomHttpResponseOptions](./kibana-plugin-core-server.customhttpresponseoptions.md) | HTTP response parameters for a response with adjustable status code. |
| [DeprecationAPIClientParams](./kibana-plugin-core-server.deprecationapiclientparams.md) | |
| [DeprecationAPIResponse](./kibana-plugin-core-server.deprecationapiresponse.md) | |
@ -75,6 +76,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
| [ElasticsearchError](./kibana-plugin-core-server.elasticsearcherror.md) | |
| [ElasticsearchServiceSetup](./kibana-plugin-core-server.elasticsearchservicesetup.md) | |
| [ElasticsearchServiceStart](./kibana-plugin-core-server.elasticsearchservicestart.md) | |
| [ElasticsearchStatusMeta](./kibana-plugin-core-server.elasticsearchstatusmeta.md) | |
| [EnvironmentMode](./kibana-plugin-core-server.environmentmode.md) | |
| [ErrorHttpResponseOptions](./kibana-plugin-core-server.errorhttpresponseoptions.md) | HTTP response parameters |
| [FakeRequest](./kibana-plugin-core-server.fakerequest.md) | Fake request object created manually by Kibana plugins. |
@ -101,6 +103,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
| [LoggerFactory](./kibana-plugin-core-server.loggerfactory.md) | The single purpose of <code>LoggerFactory</code> interface is to define a way to retrieve a context-based logger instance. |
| [LogMeta](./kibana-plugin-core-server.logmeta.md) | Contextual metadata |
| [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. |
| [OnPreResponseExtensions](./kibana-plugin-core-server.onpreresponseextensions.md) | Additional data to extend a response. |
@ -162,15 +165,18 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
| [SavedObjectsResolveImportErrorsOptions](./kibana-plugin-core-server.savedobjectsresolveimporterrorsoptions.md) | Options to control the "resolve import" operation. |
| [SavedObjectsServiceSetup](./kibana-plugin-core-server.savedobjectsservicesetup.md) | Saved Objects is Kibana's data persistence mechanism allowing plugins to use Elasticsearch for storing and querying state. The SavedObjectsServiceSetup API exposes methods for registering Saved Object types, creating and registering Saved Object client wrappers and factories. |
| [SavedObjectsServiceStart](./kibana-plugin-core-server.savedobjectsservicestart.md) | Saved Objects is Kibana's data persisentence mechanism allowing plugins to use Elasticsearch for storing and querying state. The SavedObjectsServiceStart API provides a scoped Saved Objects client for interacting with Saved Objects. |
| [SavedObjectStatusMeta](./kibana-plugin-core-server.savedobjectstatusmeta.md) | Meta information about the SavedObjectService's status. Available to plugins via [CoreSetup.status](./kibana-plugin-core-server.coresetup.status.md)<!-- -->. |
| [SavedObjectsType](./kibana-plugin-core-server.savedobjectstype.md) | |
| [SavedObjectsTypeManagementDefinition](./kibana-plugin-core-server.savedobjectstypemanagementdefinition.md) | Configuration options for the [type](./kibana-plugin-core-server.savedobjectstype.md)<!-- -->'s management section. |
| [SavedObjectsTypeMappingDefinition](./kibana-plugin-core-server.savedobjectstypemappingdefinition.md) | Describe a saved object type mapping. |
| [SavedObjectsUpdateOptions](./kibana-plugin-core-server.savedobjectsupdateoptions.md) | |
| [SavedObjectsUpdateResponse](./kibana-plugin-core-server.savedobjectsupdateresponse.md) | |
| [ServiceStatus](./kibana-plugin-core-server.servicestatus.md) | The current status of a service at a point in time. |
| [SessionCookieValidationResult](./kibana-plugin-core-server.sessioncookievalidationresult.md) | Return type from a function to validate cookie contents. |
| [SessionStorage](./kibana-plugin-core-server.sessionstorage.md) | Provides an interface to store and retrieve data across requests. |
| [SessionStorageCookieOptions](./kibana-plugin-core-server.sessionstoragecookieoptions.md) | Configuration used to create HTTP session storage based on top of cookie mechanism. |
| [SessionStorageFactory](./kibana-plugin-core-server.sessionstoragefactory.md) | SessionStorage factory to bind one to an incoming request |
| [StatusServiceSetup](./kibana-plugin-core-server.statusservicesetup.md) | API for accessing status of Core and this plugin's dependencies as well as for customizing this plugin's status. |
| [StringValidationRegex](./kibana-plugin-core-server.stringvalidationregex.md) | StringValidation with regex object |
| [StringValidationRegexString](./kibana-plugin-core-server.stringvalidationregexstring.md) | StringValidation as regex string |
| [UiSettingsParams](./kibana-plugin-core-server.uisettingsparams.md) | UiSettings parameters defined by the plugins. |
@ -184,6 +190,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
| Variable | Description |
| --- | --- |
| [kibanaResponseFactory](./kibana-plugin-core-server.kibanaresponsefactory.md) | Set of helpers used to create <code>KibanaResponse</code> to form HTTP response on an incoming request. Should be returned as a result of [RequestHandler](./kibana-plugin-core-server.requesthandler.md) execution. |
| [ServiceStatusLevels](./kibana-plugin-core-server.servicestatuslevels.md) | The current "level" of availability of a service. |
| [validBodyOutput](./kibana-plugin-core-server.validbodyoutput.md) | The set of valid body.output |
## Type Aliases
@ -256,6 +263,7 @@ The plugin integrates with the core system via lifecycle events: `setup`<!-- -->
| [SavedObjectsClientWrapperFactory](./kibana-plugin-core-server.savedobjectsclientwrapperfactory.md) | Describes the factory used to create instances of Saved Objects Client Wrappers. |
| [SavedObjectsFieldMapping](./kibana-plugin-core-server.savedobjectsfieldmapping.md) | Describe a [saved object type mapping](./kibana-plugin-core-server.savedobjectstypemappingdefinition.md) field.<!-- -->Please refer to [elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html) For the mapping documentation |
| [ScopeableRequest](./kibana-plugin-core-server.scopeablerequest.md) | A user credentials container. It accommodates the necessary auth credentials to impersonate the current user.<!-- -->See [KibanaRequest](./kibana-plugin-core-server.kibanarequest.md)<!-- -->. |
| [ServiceStatusLevel](./kibana-plugin-core-server.servicestatuslevel.md) | A convenience type that represents the union of each value in [ServiceStatusLevels](./kibana-plugin-core-server.servicestatuslevels.md)<!-- -->. |
| [SharedGlobalConfig](./kibana-plugin-core-server.sharedglobalconfig.md) | |
| [StartServicesAccessor](./kibana-plugin-core-server.startservicesaccessor.md) | Allows plugins to get access to APIs available in start inside async handlers. Promise will not resolve until Core and plugin dependencies have completed <code>start</code>. This should only be used inside handlers registered during <code>setup</code> that will only be executed after <code>start</code> lifecycle. |
| [StringValidation](./kibana-plugin-core-server.stringvalidation.md) | Allows regex objects or a regex string |

View file

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [NodesVersionCompatibility](./kibana-plugin-core-server.nodesversioncompatibility.md) &gt; [incompatibleNodes](./kibana-plugin-core-server.nodesversioncompatibility.incompatiblenodes.md)
## NodesVersionCompatibility.incompatibleNodes property
<b>Signature:</b>
```typescript
incompatibleNodes: NodeInfo[];
```

View file

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [NodesVersionCompatibility](./kibana-plugin-core-server.nodesversioncompatibility.md) &gt; [isCompatible](./kibana-plugin-core-server.nodesversioncompatibility.iscompatible.md)
## NodesVersionCompatibility.isCompatible property
<b>Signature:</b>
```typescript
isCompatible: boolean;
```

View file

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [NodesVersionCompatibility](./kibana-plugin-core-server.nodesversioncompatibility.md) &gt; [kibanaVersion](./kibana-plugin-core-server.nodesversioncompatibility.kibanaversion.md)
## NodesVersionCompatibility.kibanaVersion property
<b>Signature:</b>
```typescript
kibanaVersion: string;
```

View file

@ -0,0 +1,22 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [NodesVersionCompatibility](./kibana-plugin-core-server.nodesversioncompatibility.md)
## NodesVersionCompatibility interface
<b>Signature:</b>
```typescript
export interface NodesVersionCompatibility
```
## Properties
| Property | Type | Description |
| --- | --- | --- |
| [incompatibleNodes](./kibana-plugin-core-server.nodesversioncompatibility.incompatiblenodes.md) | <code>NodeInfo[]</code> | |
| [isCompatible](./kibana-plugin-core-server.nodesversioncompatibility.iscompatible.md) | <code>boolean</code> | |
| [kibanaVersion](./kibana-plugin-core-server.nodesversioncompatibility.kibanaversion.md) | <code>string</code> | |
| [message](./kibana-plugin-core-server.nodesversioncompatibility.message.md) | <code>string</code> | |
| [warningNodes](./kibana-plugin-core-server.nodesversioncompatibility.warningnodes.md) | <code>NodeInfo[]</code> | |

View file

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [NodesVersionCompatibility](./kibana-plugin-core-server.nodesversioncompatibility.md) &gt; [message](./kibana-plugin-core-server.nodesversioncompatibility.message.md)
## NodesVersionCompatibility.message property
<b>Signature:</b>
```typescript
message?: string;
```

View file

@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [NodesVersionCompatibility](./kibana-plugin-core-server.nodesversioncompatibility.md) &gt; [warningNodes](./kibana-plugin-core-server.nodesversioncompatibility.warningnodes.md)
## NodesVersionCompatibility.warningNodes property
<b>Signature:</b>
```typescript
warningNodes: NodeInfo[];
```

View file

@ -0,0 +1,20 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectStatusMeta](./kibana-plugin-core-server.savedobjectstatusmeta.md)
## SavedObjectStatusMeta interface
Meta information about the SavedObjectService's status. Available to plugins via [CoreSetup.status](./kibana-plugin-core-server.coresetup.status.md)<!-- -->.
<b>Signature:</b>
```typescript
export interface SavedObjectStatusMeta
```
## Properties
| Property | Type | Description |
| --- | --- | --- |
| [migratedIndices](./kibana-plugin-core-server.savedobjectstatusmeta.migratedindices.md) | <code>{</code><br/><code> [status: string]: number;</code><br/><code> skipped: number;</code><br/><code> migrated: number;</code><br/><code> }</code> | |

View file

@ -0,0 +1,15 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [SavedObjectStatusMeta](./kibana-plugin-core-server.savedobjectstatusmeta.md) &gt; [migratedIndices](./kibana-plugin-core-server.savedobjectstatusmeta.migratedindices.md)
## SavedObjectStatusMeta.migratedIndices property
<b>Signature:</b>
```typescript
migratedIndices: {
[status: string]: number;
skipped: number;
migrated: number;
};
```

View file

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [ServiceStatus](./kibana-plugin-core-server.servicestatus.md) &gt; [detail](./kibana-plugin-core-server.servicestatus.detail.md)
## ServiceStatus.detail property
A more detailed description of the service status.
<b>Signature:</b>
```typescript
detail?: string;
```

View file

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [ServiceStatus](./kibana-plugin-core-server.servicestatus.md) &gt; [documentationUrl](./kibana-plugin-core-server.servicestatus.documentationurl.md)
## ServiceStatus.documentationUrl property
A URL to open in a new tab about how to resolve or troubleshoot the problem.
<b>Signature:</b>
```typescript
documentationUrl?: string;
```

View file

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [ServiceStatus](./kibana-plugin-core-server.servicestatus.md) &gt; [level](./kibana-plugin-core-server.servicestatus.level.md)
## ServiceStatus.level property
The current availability level of the service.
<b>Signature:</b>
```typescript
level: ServiceStatusLevel;
```

View file

@ -0,0 +1,24 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [ServiceStatus](./kibana-plugin-core-server.servicestatus.md)
## ServiceStatus interface
The current status of a service at a point in time.
<b>Signature:</b>
```typescript
export interface ServiceStatus<Meta extends Record<string, any> | unknown = unknown>
```
## Properties
| Property | Type | Description |
| --- | --- | --- |
| [detail](./kibana-plugin-core-server.servicestatus.detail.md) | <code>string</code> | A more detailed description of the service status. |
| [documentationUrl](./kibana-plugin-core-server.servicestatus.documentationurl.md) | <code>string</code> | A URL to open in a new tab about how to resolve or troubleshoot the problem. |
| [level](./kibana-plugin-core-server.servicestatus.level.md) | <code>ServiceStatusLevel</code> | The current availability level of the service. |
| [meta](./kibana-plugin-core-server.servicestatus.meta.md) | <code>Meta</code> | Any JSON-serializable data to be included in the HTTP API response. Useful for providing more fine-grained, machine-readable information about the service status. May include status information for underlying features. |
| [summary](./kibana-plugin-core-server.servicestatus.summary.md) | <code>string</code> | A high-level summary of the service status. |

View file

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [ServiceStatus](./kibana-plugin-core-server.servicestatus.md) &gt; [meta](./kibana-plugin-core-server.servicestatus.meta.md)
## ServiceStatus.meta property
Any JSON-serializable data to be included in the HTTP API response. Useful for providing more fine-grained, machine-readable information about the service status. May include status information for underlying features.
<b>Signature:</b>
```typescript
meta?: Meta;
```

View file

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [ServiceStatus](./kibana-plugin-core-server.servicestatus.md) &gt; [summary](./kibana-plugin-core-server.servicestatus.summary.md)
## ServiceStatus.summary property
A high-level summary of the service status.
<b>Signature:</b>
```typescript
summary: string;
```

View file

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [ServiceStatusLevel](./kibana-plugin-core-server.servicestatuslevel.md)
## ServiceStatusLevel type
A convenience type that represents the union of each value in [ServiceStatusLevels](./kibana-plugin-core-server.servicestatuslevels.md)<!-- -->.
<b>Signature:</b>
```typescript
export declare type ServiceStatusLevel = typeof ServiceStatusLevels[keyof typeof ServiceStatusLevels];
```

View file

@ -0,0 +1,37 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [ServiceStatusLevels](./kibana-plugin-core-server.servicestatuslevels.md)
## ServiceStatusLevels variable
The current "level" of availability of a service.
<b>Signature:</b>
```typescript
ServiceStatusLevels: Readonly<{
available: Readonly<{
toString: () => "available";
valueOf: () => 0;
}>;
degraded: Readonly<{
toString: () => "degraded";
valueOf: () => 1;
}>;
unavailable: Readonly<{
toString: () => "unavailable";
valueOf: () => 2;
}>;
critical: Readonly<{
toString: () => "critical";
valueOf: () => 3;
}>;
}>
```
## Remarks
The values implement `valueOf` to allow for easy comparisons between status levels with &lt;<!-- -->, &gt;<!-- -->, etc. Higher values represent higher severities. Note that the default `Array.prototype.sort` implementation does not correctly sort these values.
A snapshot serializer is available in `src/core/server/test_utils` to ease testing of these values with Jest.

View file

@ -0,0 +1,13 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [StatusServiceSetup](./kibana-plugin-core-server.statusservicesetup.md) &gt; [core$](./kibana-plugin-core-server.statusservicesetup.core_.md)
## StatusServiceSetup.core$ property
Current status for all Core services.
<b>Signature:</b>
```typescript
core$: Observable<CoreStatus>;
```

View file

@ -0,0 +1,20 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-core-server](./kibana-plugin-core-server.md) &gt; [StatusServiceSetup](./kibana-plugin-core-server.statusservicesetup.md)
## StatusServiceSetup interface
API for accessing status of Core and this plugin's dependencies as well as for customizing this plugin's status.
<b>Signature:</b>
```typescript
export interface StatusServiceSetup
```
## Properties
| Property | Type | Description |
| --- | --- | --- |
| [core$](./kibana-plugin-core-server.statusservicesetup.core_.md) | <code>Observable&lt;CoreStatus&gt;</code> | Current status for all Core services. |

View file

@ -0,0 +1,15 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) &gt; [createSearchSource](./kibana-plugin-plugins-data-public.createsearchsource.md)
## createSearchSource variable
Deserializes a json string and a set of referenced objects to a `SearchSource` instance. Use this method to re-create the search source serialized using `searchSource.serialize`<!-- -->.
This function is a factory function that returns the actual utility when calling it with the required service dependency (index patterns contract). A pre-wired version is also exposed in the start contract of the data plugin as part of the search service
<b>Signature:</b>
```typescript
createSearchSource: (indexPatterns: Pick<import("../../index_patterns/index_patterns").IndexPatternsService, "get" | "clearCache" | "getFieldsForTimePattern" | "getFieldsForWildcard" | "getIds" | "getTitles" | "getFields" | "getCache" | "getDefault" | "make">) => (searchSourceJson: string, references: SavedObjectReference[]) => Promise<SearchSource>
```

View file

@ -102,6 +102,7 @@
| [castEsToKbnFieldTypeName](./kibana-plugin-plugins-data-public.castestokbnfieldtypename.md) | Get the KbnFieldType name for an esType string |
| [connectToQueryState](./kibana-plugin-plugins-data-public.connecttoquerystate.md) | Helper to setup two-way syncing of global data and a state container |
| [createSavedQueryService](./kibana-plugin-plugins-data-public.createsavedqueryservice.md) | |
| [createSearchSource](./kibana-plugin-plugins-data-public.createsearchsource.md) | Deserializes a json string and a set of referenced objects to a <code>SearchSource</code> instance. Use this method to re-create the search source serialized using <code>searchSource.serialize</code>.<!-- -->This function is a factory function that returns the actual utility when calling it with the required service dependency (index patterns contract). A pre-wired version is also exposed in the start contract of the data plugin as part of the search service |
| [ES\_SEARCH\_STRATEGY](./kibana-plugin-plugins-data-public.es_search_strategy.md) | |
| [esFilters](./kibana-plugin-plugins-data-public.esfilters.md) | |
| [esKuery](./kibana-plugin-plugins-data-public.eskuery.md) | |

View file

@ -38,6 +38,7 @@ export declare class SearchSource
| [getParent()](./kibana-plugin-plugins-data-public.searchsource.getparent.md) | | Get the parent of this SearchSource {<!-- -->undefined\|searchSource<!-- -->} |
| [getSearchRequestBody()](./kibana-plugin-plugins-data-public.searchsource.getsearchrequestbody.md) | | |
| [onRequestStart(handler)](./kibana-plugin-plugins-data-public.searchsource.onrequeststart.md) | | Add a handler that will be notified whenever requests start |
| [serialize()](./kibana-plugin-plugins-data-public.searchsource.serialize.md) | | Serializes the instance to a JSON string and a set of referenced objects. Use this method to get a representation of the search source which can be stored in a saved object.<!-- -->The references returned by this function can be mixed with other references in the same object, however make sure there are no name-collisions. The references will be named <code>kibanaSavedObjectMeta.searchSourceJSON.index</code> and <code>kibanaSavedObjectMeta.searchSourceJSON.filter[&lt;number&gt;].meta.index</code>.<!-- -->Using <code>createSearchSource</code>, the instance can be re-created. |
| [setField(field, value)](./kibana-plugin-plugins-data-public.searchsource.setfield.md) | | |
| [setFields(newFields)](./kibana-plugin-plugins-data-public.searchsource.setfields.md) | | |
| [setParent(parent, options)](./kibana-plugin-plugins-data-public.searchsource.setparent.md) | | Set a searchSource that this source should inherit from |

View file

@ -0,0 +1,27 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) &gt; [SearchSource](./kibana-plugin-plugins-data-public.searchsource.md) &gt; [serialize](./kibana-plugin-plugins-data-public.searchsource.serialize.md)
## SearchSource.serialize() method
Serializes the instance to a JSON string and a set of referenced objects. Use this method to get a representation of the search source which can be stored in a saved object.
The references returned by this function can be mixed with other references in the same object, however make sure there are no name-collisions. The references will be named `kibanaSavedObjectMeta.searchSourceJSON.index` and `kibanaSavedObjectMeta.searchSourceJSON.filter[<number>].meta.index`<!-- -->.
Using `createSearchSource`<!-- -->, the instance can be re-created.
<b>Signature:</b>
```typescript
serialize(): {
searchSourceJSON: string;
references: SavedObjectReference[];
};
```
<b>Returns:</b>
`{
searchSourceJSON: string;
references: SavedObjectReference[];
}`

View file

@ -23,7 +23,6 @@
| Function | Description |
| --- | --- |
| [getDefaultSearchParams(config)](./kibana-plugin-plugins-data-server.getdefaultsearchparams.md) | |
| [getTotalLoaded({ total, failed, successful })](./kibana-plugin-plugins-data-server.gettotalloaded.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) | |

View file

@ -18,9 +18,9 @@ For more information on alerting concepts and the types of alerts and actions av
[float]
==== Finding alerts
The *Alerts* tab lists all alerts in the current space, including summary information about their execution frequency, tags, and type.
The *Alerts* tab lists all alerts in the current space, including summary information about their execution frequency, tags, and type.
The *search bar* can be used to quickly find alerts by name or tag.
The *search bar* can be used to quickly find alerts by name or tag.
[role="screenshot"]
image::images/alerts-filter-by-search.png[Filtering the alerts list using the search bar]
@ -30,7 +30,7 @@ The *type* dropdown lets you filter to a subset of alert types.
[role="screenshot"]
image::images/alerts-filter-by-type.png[Filtering the alerts list by types of alert]
The *Action type* dropdown lets you filter by the type of action used in the alert.
The *Action type* dropdown lets you filter by the type of action used in the alert.
[role="screenshot"]
image::images/alerts-filter-by-action-type.png[Filtering the alert list by type of action]
@ -39,16 +39,16 @@ image::images/alerts-filter-by-action-type.png[Filtering the alert list by type
[[create-edit-alerts]]
==== Creating and editing alerts
Many alerts must be created within the context of a {kib} app like <<xpack-infra, Metrics>>, <<xpack-apm, APM>>, or <<xpack-uptime, Uptime>>, but others are generic. Generic alert types can be created in the *Alerts* management UI by clicking the *Create* button. This will launch a flyout that guides you through selecting an alert type and configuring it's properties. Refer to <<alert-types>> for details on what types of alerts are available and how to configure them.
Many alerts must be created within the context of a {kib} app like <<xpack-infra, Metrics>>, <<xpack-apm, APM>>, or <<xpack-uptime, Uptime>>, but others are generic. Generic alert types can be created in the *Alerts* management UI by clicking the *Create* button. This will launch a flyout that guides you through selecting an alert type and configuring it's properties. Refer to <<alert-types>> for details on what types of alerts are available and how to configure them.
After an alert is created, you can re-open the flyout and change an alerts properties by clicking the *Edit* button shown on each row of the alert listing.
After an alert is created, you can re-open the flyout and change an alerts properties by clicking the *Edit* button shown on each row of the alert listing.
[float]
[[controlling-alerts]]
==== Controlling alerts
The alert listing allows you to quickly mute/unmute, disable/enable, and delete individual alerts by clicking the action button at the right of each row.
The alert listing allows you to quickly mute/unmute, disable/enable, and delete individual alerts by clicking the action button.
[role="screenshot"]
image:management/alerting/images/individual-mute-disable.png[The actions button allows an individual alert to be muted, disabled, or deleted]
@ -56,4 +56,4 @@ image:management/alerting/images/individual-mute-disable.png[The actions button
These operations can also be performed in bulk by multi-selecting alerts and clicking the *Manage alerts* button:
[role="screenshot"]
image:management/alerting/images/bulk-mute-disable.png[The Manage alerts button lets you mute/unmute, enable/disable, and delete in bulk]
image:management/alerting/images/bulk-mute-disable.png[The Manage alerts button lets you mute/unmute, enable/disable, and delete in bulk]

View file

@ -15,7 +15,7 @@ image::images/connector-listing.png[Example connector listing in the Alerts and
[float]
==== Connector list
The *Connectors* tab lists all connectors in the current space. The *search bar* can be used to find specific connectors by name and/or type.
The *Connectors* tab lists all connectors in the current space. The *search bar* can be used to find specific connectors by name and/or type.
[role="screenshot"]
image::images/connector-filter-by-search.png[Filtering the connector list using the search bar]
@ -26,12 +26,12 @@ The *type* dropdown also lets you filter to a subset of action types.
[role="screenshot"]
image::images/connector-filter-by-type.png[Filtering the connector list by types of actions]
The *Actions* column indicates the number of actions that reference the connector. This count helps you confirm a connector is unused before you delete it, and tells you how many actions will be affected when a connector is modified.
The *Actions* column indicates the number of actions that reference the connector. This count helps you confirm a connector is unused before you delete it, and tells you how many actions will be affected when a connector is modified.
[role="screenshot"]
image::images/connector-action-count.png[Filtering the connector list by types of actions]
You can delete individual connectors using the trash icon on the right of each row. Connectors can also be deleted in bulk by multi-selecting them and clicking the *Delete* button to the left of the search box.
You can delete individual connectors using the trash icon. Connectors can also be deleted in bulk by multi-selecting them and clicking the *Delete* button to the left of the search box.
[role="screenshot"]
image::images/connector-delete.png[Deleting connectors individually or in bulk]
@ -44,4 +44,4 @@ When this happens the action will fail to execute, and appear as errors in the {
==== Creating a new connector
New connectors can be created by clicking the *Create connector* button, which will guide you to select the type of connector and configure it's properties. Refer to <<action-types>> for the types of connectors available and how to configure them. Once you create a connector it will be made available to you anytime you set up an action in the current space.
New connectors can be created by clicking the *Create connector* button, which will guide you to select the type of connector and configure it's properties. Refer to <<action-types>> for the types of connectors available and how to configure them. Once you create a connector it will be made available to you anytime you set up an action in the current space.

View file

@ -38,7 +38,6 @@ image:management/index-patterns/images/rollup-index-pattern.png["Menu with rollu
Just start typing in the *Index pattern* field, and {kib} looks for
the names of {es} indices that match your input. Make sure that the name of the
index pattern is unique.
To include system indices in your search, toggle the switch in the upper right.
[role="screenshot"]
image:management/index-patterns/images/create-index-pattern.png["Create index pattern"]

View file

@ -25,7 +25,7 @@ the *Index patterns* overview.
[role="screenshot"]
image::management/index-patterns/images/new-index-pattern.png["Index files and data types"]
Use the icons in the upper right to perform the following actions:
Use the icons to perform the following actions:
* [[set-default-pattern]]*Set the default index pattern.* {kib} uses a badge to make users
aware of which index pattern is the default. The first pattern

View file

@ -42,8 +42,8 @@ image::images/management_create_rollup_job.png[][Wizard that walks you through c
=== Start, stop, and delete rollup jobs
Once youve saved a rollup job, youll see it the *Rollup Jobs* overview page,
where you can drill down for further investigation. The *Manage* menu in
the lower right enables you to start, stop, and delete the rollup job.
where you can drill down for further investigation. The *Manage* menu enables
you to start, stop, and delete the rollup job.
You must first stop a rollup job before deleting it.
[role="screenshot"]

View file

@ -37,7 +37,6 @@ the Elasticsearch responses are shown on the *Layer add panel* and the indexed d
appears on the map. The geospatial data on the map
should be identical to the locally-previewed data, but now it's indexed data from Elasticsearch.
. To continue adding data to the map, click *Add layer* in the lower
right-hand corner.
. To continue adding data to the map, click *Add layer*.
. In *Layer settings*, adjust any settings or <<maps-vector-style-properties, properties>> as needed.
. Click *Save & close*.

View file

@ -55,14 +55,14 @@ auto-populate *Index type* with either {ref}/geo-point.html[geo_point] or
{ref}/geo-shape.html[geo_shape] and *Index name* with
`<file name>`.
. Click *Import file* in the lower right.
. Click *Import file*.
+
You'll see activity as the GeoJSON Upload utility creates a new index
and index pattern for the data set. When the process is complete, you should
receive messages that the creation of the new index and index pattern
were successful.
. Click *Add layer* in the bottom right.
. Click *Add layer*.
. In *Layer settings*, adjust settings and <<maps-vector-style-properties, properties>> as needed.
. Click *Save & close*.

View file

@ -80,7 +80,7 @@ To symbolize countries by web traffic, you'll need to augment the world country
To do this, you'll create a <<terms-join, term join>> to link the vector source *World Countries* to
the {es} index `kibana_sample_data_logs` on the shared key iso2 = geo.src.
. Click plus image:maps/images/gs_plus_icon.png[] to the right of *Term Joins* label.
. Click plus image:maps/images/gs_plus_icon.png[] next to the *Term Joins* label.
. Click *Join --select--*
. Set *Left field* to *ISO 3166-1 alpha-2 code*.
. Set *Right source* to *kibana_sample_data_logs*.
@ -238,7 +238,7 @@ The *machine.os.keyword: osx* filter appears in the dashboard query bar.
+
. Click the *x* to remove the *machine.os.keyword: osx* filter.
. In the map, click in the United States vector.
. Click plus image:maps/images/gs_plus_icon.png[] to the right of *iso2* row in the tooltip.
. Click plus image:maps/images/gs_plus_icon.png[] next to the *iso2* row in the tooltip.
+
Both the visualizations and the map are filtered to only show documents where *geo.src* is *US*.
The *geo.src: US* filter appears in the dashboard query bar.
@ -247,4 +247,3 @@ Your dashboard should look like this:
+
[role="screenshot"]
image::maps/images/gs_dashboard_with_terms_filter.png[]

View file

@ -4,7 +4,7 @@
**Elastic Maps** embeds the search bar for real-time search.
Only layers requesting data from {es} are filtered when you submit a search request.
Layers narrowed by the search context contain the filter icon image:maps/images/filter_icon.png[] to the right of layer name in the legend.
Layers narrowed by the search context contain the filter icon image:maps/images/filter_icon.png[] next to the layer name in the legend.
You can create a layer that requests data from {es} from the following:

View file

@ -2,7 +2,7 @@
[[defining-alerts]]
== Defining alerts
{kib} alerts can be created in a variety of apps including <<xpack-apm,*APM*>>, <<xpack-infra,*Metrics*>>, <<xpack-siem,*SIEM*>>, <<xpack-uptime,*Uptime*>> and from <<management,*Management*>> UI. While alerting details may differ from app to app, they share a common interface for defining and configuring alerts that this section describes in more detail.
{kib} alerts can be created in a variety of apps including <<xpack-apm,*APM*>>, <<xpack-infra,*Metrics*>>, <<xpack-siem,*SIEM*>>, <<xpack-uptime,*Uptime*>> and from <<management,*Management*>> UI. While alerting details may differ from app to app, they share a common interface for defining and configuring alerts that this section describes in more detail.
[float]
=== Alert flyout
@ -25,20 +25,20 @@ All alert share the following four properties in common:
image::images/alert-flyout-general-details.png[All alerts have name, tags, check every, and re-notify every properties in common]
Name:: The name of the alert. While this name does not have to be unique, the name can be referenced in actions and also appears in the searchable alert listing in the management UI. A distinctive name can help identify and find an alert.
Tags:: A list of tag names that can be applied to an alert. Tags can help you organize and find alerts, because tags appear in the alert listing in the management UI which is searchable by tag.
Tags:: A list of tag names that can be applied to an alert. Tags can help you organize and find alerts, because tags appear in the alert listing in the management UI which is searchable by tag.
Check every:: This value determines how frequently the alert conditions below are checked. Note that the timing of background alert checks are not guaranteed, particularly for intervals of less than 10 seconds. See <<alerting-scale-performance>> for more information.
Re-notify every:: This value limits how often actions are repeated when an alert instance remains active across alert checks. See <<alerting-concepts-suppressing-duplicate-notifications>> for more information.
Re-notify every:: This value limits how often actions are repeated when an alert instance remains active across alert checks. See <<alerting-concepts-suppressing-duplicate-notifications>> for more information.
[float]
[[defining-alerts-type-conditions]]
=== Alert type and conditions
Depending upon the {kib} app and context, you may be prompted to choose the type of alert you wish to create. Some apps will pre-select the type of alert for you.
Depending upon the {kib} app and context, you may be prompted to choose the type of alert you wish to create. Some apps will pre-select the type of alert for you.
[role="screenshot"]
image::images/alert-flyout-alert-type-selection.png[Choosing the type of alert to create]
Each alert type provides its own way of defining the conditions to detect, but an expression formed by a series of clauses is a common pattern. Each clause has a UI control that allows you to define the clause. For example, in an index threshold alert the `WHEN` clause allows you to select an aggregation operation to apply to a numeric field.
Each alert type provides its own way of defining the conditions to detect, but an expression formed by a series of clauses is a common pattern. Each clause has a UI control that allows you to define the clause. For example, in an index threshold alert the `WHEN` clause allows you to select an aggregation operation to apply to a numeric field.
[role="screenshot"]
image::images/alert-flyout-alert-conditions.png[UI for defining alert conditions on an index threshold alert]
@ -52,19 +52,19 @@ To add an action to an alert, you first select the type of action:
[role="screenshot"]
image::images/alert-flyout-action-type-selection.png[UI for selecting an action type]
Each action must specify a <<alerting-concepts-connectors, connector>> instance. If no connectors exist for that action type, click "Add new" to create one.
Each action must specify a <<alerting-concepts-connectors, connector>> instance. If no connectors exist for that action type, click "Add new" to create one.
Each action type exposes different properties. For example an email action allows you to set the recipients, the subject, and a message body in markdown format. See <<action-types>> for details on the types of actions provided by {kib} and their properties.
Each action type exposes different properties. For example an email action allows you to set the recipients, the subject, and a message body in markdown format. See <<action-types>> for details on the types of actions provided by {kib} and their properties.
[role="screenshot"]
image::images/alert-flyout-action-details.png[UI for defining an email action]
Using the https://mustache.github.io/[Mustache] template syntax `{{variable name}}`, you can pass alert values at the time a condition is detected to an action. Available variables differ by alert type, and a list can be accessed using the "add variable" button at the right of the text box.
Using the https://mustache.github.io/[Mustache] template syntax `{{variable name}}`, you can pass alert values at the time a condition is detected to an action. Available variables differ by alert type, and a list can be accessed using the "add variable" button.
[role="screenshot"]
image::images/alert-flyout-action-variables.png[Passing alert values to an action]
You can attach more than one action. Clicking the "Add action" button will prompt you to select another alert type and repeat the above steps again.
You can attach more than one action. Clicking the "Add action" button will prompt you to select another alert type and repeat the above steps again.
[role="screenshot"]
image::images/alert-flyout-add-action.png[You can add multiple actions on an alert]
@ -77,4 +77,4 @@ Actions are not required on alerts. In some cases you may want to run an alert w
[float]
=== Managing alerts
To modify an alert after it was created, including muting or disabling it, use the <<alert-management, alert listing in the Management UI>>.
To modify an alert after it was created, including muting or disabling it, use the <<alert-management, alert listing in the Management UI>>.

View file

@ -163,7 +163,8 @@ If you are using an *on-premises* Elastic Stack deployment with <<using-kibana-w
[[alerting-security]]
== Security
To access alerting in a space, a user must have access to one of the following features:
To access alerting in a space, a user must have access to one of the following features:
* <<xpack-apm,*APM*>>
* <<xpack-infra,*Metrics*>>
* <<xpack-siem,*SIEM*>>

View file

@ -90,7 +90,7 @@ In *Edit* mode, you can move, resize, customize, and delete panels to suit your
* To move a panel, click and hold the panel header and drag to the new location.
[[resizing-containers]]
* To resize a panel, click the resize control on the lower right and drag
* To resize a panel, click the resize control and drag
to the new dimensions.
* To toggle the use of margins and panel titles, use the *Options* menu.

View file

@ -4,13 +4,29 @@
[partintro]
--
The *Dev Tools* page contains development tools that you can use to interact
with your data in Kibana.
*Dev Tools* contains tools that you can use to interact
with your data.
* <<console-kibana, Console>>
* <<xpack-profiler, Search Profiler>>
* <<xpack-grokdebugger, Grok Debugger>>
[cols="2"]
|===
a| <<console-kibana, Console>>
| Interact with the REST API of Elasticsearch, including sending requests
and viewing API documentation.
a| <<xpack-profiler, Search&nbsp;Profiler>>
| Inspect and analyze your search queries.
a| <<xpack-grokdebugger, Grok&nbsp;Debugger&nbsp;&nbsp;&nbsp;>>
| Build and debug grok patterns before you use them in your data processing pipelines.
a| <<painlesslab, Painless&nbsp;Lab>>
| beta:[] Test and debug Painless scripts in real-time.
|===
--
@ -19,3 +35,5 @@ include::{kib-repo-dir}/dev-tools/console/console.asciidoc[]
include::{kib-repo-dir}/dev-tools/searchprofiler/index.asciidoc[]
include::{kib-repo-dir}/dev-tools/grokdebugger/index.asciidoc[]
include::{kib-repo-dir}/dev-tools/painlesslab/index.asciidoc[]

View file

@ -33,7 +33,7 @@ which has a pre-built index pattern.
By default, *Discover* shows data for the last 15 minutes.
If you have a time-based index, and no data displays,
you might need to increase the time range. Using the <<set-time-filter, time filter>> in the upper right,
you might need to increase the time range. Using the <<set-time-filter, time filter>>,
you can specify a common or recently-used time range, a relative time
from now, or an absolute time range.

View file

@ -38,7 +38,7 @@ image::user/graph/images/graph-url-connections.png["URL connections"]
[role="screenshot"]
image::user/graph/images/graph-link-summary.png["Link summary"]
. Use the control bar on the right to explore
. Use the control bar to explore
additional connections:
+
* To display additional vertices that connect to your graph, click the expand icon
@ -70,7 +70,7 @@ select *Edit settings*.
To change the color and label of selected vertices,
click the style icon image:user/graph/images/graph-style-button.png[Style]
in the control bar on the right.
in the control bar.
[float]

View file

@ -14,8 +14,8 @@ image::user/monitoring/images/monitoring-beats.jpg["Monitoring Beats",link="imag
To view an overview of the Beats data in the cluster, click *Overview*. The
overview page has a section for activity in the last day, which is a real-time
sample of data. The summary bar and charts follow the typical paradigm
of data in the Monitoring UI, which is bound to the span of the time filter in
the top right corner of the page. This overview page can therefore show
of data in the Monitoring UI, which is bound to the span of the time filter.
This overview page can therefore show
up-to-date or historical information.
To view a listing of the individual Beat instances in the cluster, click *Beats*.

View file

@ -38,7 +38,7 @@ you'll see two places highlighted in green:
* The visualization builder pane
* The *X-axis* or *Y-axis* fields in the right column
* The *X-axis* or *Y-axis* fields
You can incorporate many fields into your visualization, and Lens uses heuristics to decide how
to apply each one to the visualization.
@ -89,8 +89,8 @@ You can switch between suggestions without losing your previous state:
[role="screenshot"]
image::images/lens_suggestions.gif[]
If you want to switch to a chart type that is not suggested, click the chart type in the
top right, then select a chart type. When there is an exclamation point (!)
If you want to switch to a chart type that is not suggested, click the chart type,
then select a chart type. When there is an exclamation point (!)
next to a chart type, Lens is unable to transfer your current data, but
still allows you to make the change.
@ -106,7 +106,7 @@ If there is a match, Lens displays the new data. All fields that do not match th
. Change the data field options, such as the aggregation or label.
.. Click *Drop a field here* or the field name in the right column.
.. Click *Drop a field here* or the field name in the column.
.. Change the options that appear depending on the type of field.
@ -168,7 +168,7 @@ image::images/lens_tutorial_2.png[Lens tutorial]
Customize your visualization to look exactly how you want.
. In the right column, click *Average of taxful_total_price*.
. Click *Average of taxful_total_price*.
.. Change the *Label* to `Sales`, or a name that you prefer for the data.
@ -180,7 +180,7 @@ six available categories.
. Look at the suggestions. None of them show an area chart, but for sales data, a stacked area chart
might make sense. To switch the chart type:
.. Click *Stacked bar chart* in the right column.
.. Click *Stacked bar chart* in the column.
.. Click *Stacked area*.
+

View file

@ -376,7 +376,7 @@
"@types/recompose": "^0.30.6",
"@types/redux-actions": "^2.6.1",
"@types/request": "^2.48.2",
"@types/selenium-webdriver": "^4.0.5",
"@types/selenium-webdriver": "4.0.9",
"@types/semver": "^5.5.0",
"@types/sinon": "^7.0.13",
"@types/strip-ansi": "^3.0.0",
@ -462,6 +462,7 @@
"load-grunt-config": "^3.0.1",
"mocha": "^7.1.1",
"mock-http-server": "1.3.0",
"ms-chromium-edge-driver": "^0.2.0",
"multistream": "^2.1.1",
"murmurhash3js": "3.0.1",
"mutation-observer": "^1.0.3",
@ -480,7 +481,7 @@
"react-textarea-autosize": "^7.1.2",
"regenerate": "^1.4.0",
"sass-lint": "^1.12.1",
"selenium-webdriver": "^4.0.0-alpha.5",
"selenium-webdriver": "^4.0.0-alpha.7",
"simple-git": "1.116.0",
"simplebar-react": "^2.1.0",
"sinon": "^7.4.2",

View file

@ -32,6 +32,7 @@
"json-stable-stringify": "^1.0.1",
"loader-utils": "^1.2.3",
"node-sass": "^4.13.0",
"normalize-path": "^3.0.0",
"postcss-loader": "^3.0.0",
"raw-loader": "^3.1.0",
"resolve-url-loader": "^3.1.1",

File diff suppressed because one or more lines are too long

View file

@ -19,6 +19,7 @@
import Path from 'path';
import normalizePath from 'normalize-path';
import { stringifyRequest } from 'loader-utils';
import webpack from 'webpack';
// @ts-ignore
@ -36,6 +37,59 @@ const ISTANBUL_PRESET_PATH = require.resolve('@kbn/babel-preset/istanbul_preset'
const PUBLIC_PATH_PLACEHOLDER = '__REPLACE_WITH_PUBLIC_PATH__';
const BABEL_PRESET_PATH = require.resolve('@kbn/babel-preset/webpack_preset');
const STATIC_BUNDLE_PLUGINS = [
// { id: 'data', dirname: 'data' },
{ id: 'kibanaReact', dirname: 'kibana_react' },
{ id: 'kibanaUtils', dirname: 'kibana_utils' },
{ id: 'esUiShared', dirname: 'es_ui_shared' },
];
/**
* Determine externals statements for require/import statements by looking
* for requests resolving to the primary public export of the data, kibanaReact,
* amd kibanaUtils plugins. If this module is being imported then rewrite
* the import to access the global `__kbnBundles__` variables and access
* the relavent properties from that global object.
*
* @param bundle
* @param context the directory containing the module which made `request`
* @param request the request for a module from a commonjs require() call or import statement
*/
function dynamicExternals(bundle: Bundle, context: string, request: string) {
// ignore imports that have loaders defined
if (request.includes('!')) {
return;
}
// don't allow any static bundle to rely on other static bundles
if (STATIC_BUNDLE_PLUGINS.some(p => bundle.id === p.id)) {
return;
}
// ignore requests that don't include a /data/public, /kibana_react/public, or
// /kibana_utils/public segment as a cheap way to avoid doing path resolution
// for paths that couldn't possibly resolve to what we're looking for
const reqToStaticBundle = STATIC_BUNDLE_PLUGINS.some(p =>
request.includes(`/${p.dirname}/public`)
);
if (!reqToStaticBundle) {
return;
}
// determine the most acurate resolution string we can without running full resolution
const rootRelative = normalizePath(
Path.relative(bundle.sourceRoot, Path.resolve(context, request))
);
for (const { id, dirname } of STATIC_BUNDLE_PLUGINS) {
if (rootRelative === `src/plugins/${dirname}/public`) {
return `__kbnBundles__['plugin/${id}']`;
}
}
// import doesn't match a root public import
return undefined;
}
export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) {
const commonConfig: webpack.Configuration = {
node: { fs: 'empty' },
@ -63,7 +117,6 @@ export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) {
// When the entry point is loaded, assign it's exported `plugin`
// value to a key on the global `__kbnBundles__` object.
library: ['__kbnBundles__', `plugin/${bundle.id}`],
libraryExport: 'plugin',
}
: {}),
},
@ -72,9 +125,16 @@ export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) {
noEmitOnErrors: true,
},
externals: {
...UiSharedDeps.externals,
},
externals: [
UiSharedDeps.externals,
function(context, request, cb) {
try {
cb(undefined, dynamicExternals(bundle, context, request));
} catch (error) {
cb(error, undefined);
}
},
],
plugins: [new CleanWebpackPlugin(), new DisallowedSyntaxPlugin()],

File diff suppressed because it is too large Load diff

View file

@ -136,7 +136,7 @@ export const schema = Joi.object()
browser: Joi.object()
.keys({
type: Joi.string()
.valid('chrome', 'firefox', 'ie')
.valid('chrome', 'firefox', 'ie', 'msedge')
.default('chrome'),
logPollingMs: Joi.number().default(100),

View file

@ -20,6 +20,13 @@
require('core-js/stable');
require('regenerator-runtime/runtime');
require('custom-event-polyfill');
if (typeof window.Event === 'object') {
// IE11 doesn't support unknown event types, required by react-use
// https://github.com/streamich/react-use/issues/73
window.Event = CustomEvent;
}
require('whatwg-fetch');
require('abortcontroller-polyfill/dist/polyfill-patch-fetch');
require('./vendor/childnode_remove_polyfill');

View file

@ -71,7 +71,7 @@ test('`loadPluginBundles` creates a script tag and loads initializer', async ()
// Setup a fake initializer as if a plugin bundle had actually been loaded.
const fakeInitializer = jest.fn();
coreWindow.__kbnBundles__['plugin/plugin-a'] = fakeInitializer;
coreWindow.__kbnBundles__['plugin/plugin-a'] = { plugin: fakeInitializer };
// Call the onload callback
fakeScriptTag.onload();
await expect(loadPromise).resolves.toEqual(fakeInitializer);

View file

@ -32,7 +32,7 @@ export type UnknownPluginInitializer = PluginInitializer<unknown, Record<string,
*/
export interface CoreWindow {
__kbnBundles__: {
[pluginBundleName: string]: UnknownPluginInitializer | undefined;
[pluginBundleName: string]: { plugin: UnknownPluginInitializer } | undefined;
};
}
@ -70,9 +70,28 @@ export const loadPluginBundle: LoadPluginBundle = <
) =>
new Promise<PluginInitializer<TSetup, TStart, TPluginsSetup, TPluginsStart>>(
(resolve, reject) => {
const script = document.createElement('script');
const coreWindow = (window as unknown) as CoreWindow;
const exportId = `plugin/${pluginName}`;
const readPluginExport = () => {
const PluginExport: any = coreWindow.__kbnBundles__[exportId];
if (typeof PluginExport?.plugin !== 'function') {
reject(
new Error(`Definition of plugin "${pluginName}" should be a function (${bundlePath}).`)
);
} else {
resolve(
PluginExport.plugin as PluginInitializer<TSetup, TStart, TPluginsSetup, TPluginsStart>
);
}
};
if (coreWindow.__kbnBundles__[exportId]) {
readPluginExport();
return;
}
const script = document.createElement('script');
// Assumes that all plugin bundles get put into the bundles/plugins subdirectory
const bundlePath = addBasePath(`/bundles/plugin/${pluginName}/${pluginName}.plugin.js`);
script.setAttribute('src', bundlePath);
@ -89,15 +108,7 @@ export const loadPluginBundle: LoadPluginBundle = <
// Wire up resolve and reject
script.onload = () => {
cleanupTag();
const initializer = coreWindow.__kbnBundles__[`plugin/${pluginName}`];
if (!initializer || typeof initializer !== 'function') {
reject(
new Error(`Definition of plugin "${pluginName}" should be a function (${bundlePath}).`)
);
} else {
resolve(initializer as PluginInitializer<TSetup, TStart, TPluginsSetup, TPluginsStart>);
}
readPluginExport();
};
script.onerror = () => {

View file

@ -26,8 +26,10 @@ import {
InternalElasticsearchServiceSetup,
ElasticsearchServiceSetup,
ElasticsearchServiceStart,
ElasticsearchStatusMeta,
} from './types';
import { NodesVersionCompatibility } from './version_check/ensure_es_version';
import { ServiceStatus, ServiceStatusLevels } from '../status';
const createScopedClusterClientMock = (): jest.Mocked<IScopedClusterClient> => ({
callAsInternalUser: jest.fn(),
@ -102,6 +104,10 @@ const createInternalSetupContractMock = () => {
warningNodes: [],
kibanaVersion: '8.0.0',
}),
status$: new BehaviorSubject<ServiceStatus<ElasticsearchStatusMeta>>({
level: ServiceStatusLevels.available,
summary: 'Elasticsearch is available',
}),
legacy: {
config$: new BehaviorSubject({} as ElasticsearchConfig),
},

View file

@ -40,6 +40,7 @@ import { InternalHttpServiceSetup, GetAuthHeaders } from '../http/';
import { InternalElasticsearchServiceSetup, ElasticsearchServiceStart } from './types';
import { CallAPIOptions } from './api_types';
import { pollEsNodesVersion } from './version_check/ensure_es_version';
import { calculateStatus$ } from './status';
/** @internal */
interface CoreClusterClients {
@ -186,6 +187,7 @@ export class ElasticsearchService
adminClient: this.adminClient,
dataClient,
createClient: this.createClient,
status$: calculateStatus$(esNodesCompatibility$),
};
}

View file

@ -31,3 +31,4 @@ export { config, configSchema, ElasticsearchConfig } from './elasticsearch_confi
export { ElasticsearchError, ElasticsearchErrorHelpers } from './errors';
export * from './api_types';
export * from './types';
export { NodesVersionCompatibility } from './version_check/ensure_es_version';

View file

@ -0,0 +1,222 @@
/*
* 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 { take } from 'rxjs/operators';
import { Subject, of } from 'rxjs';
import { calculateStatus$ } from './status';
import { ServiceStatusLevels, ServiceStatus } from '../status';
import { ServiceStatusLevelSnapshotSerializer } from '../status/test_utils';
import { NodesVersionCompatibility } from './version_check/ensure_es_version';
expect.addSnapshotSerializer(ServiceStatusLevelSnapshotSerializer);
const nodeInfo = {
version: '1.1.1',
ip: '1.1.1.1',
http: {
publish_address: 'https://1.1.1.1:9200',
},
name: 'node1',
};
describe('calculateStatus', () => {
it('starts in unavailable', async () => {
expect(
await calculateStatus$(new Subject())
.pipe(take(1))
.toPromise()
).toEqual({
level: ServiceStatusLevels.unavailable,
summary: 'Waiting for Elasticsearch',
meta: {
warningNodes: [],
incompatibleNodes: [],
},
});
});
it('changes to available when isCompatible and no warningNodes', async () => {
expect(
await calculateStatus$(
of({ isCompatible: true, kibanaVersion: '1.1.1', warningNodes: [], incompatibleNodes: [] })
)
.pipe(take(2))
.toPromise()
).toEqual({
level: ServiceStatusLevels.available,
summary: 'Elasticsearch is available',
meta: {
warningNodes: [],
incompatibleNodes: [],
},
});
});
it('changes to degraded when isCompatible and warningNodes present', async () => {
expect(
await calculateStatus$(
of({
isCompatible: true,
kibanaVersion: '1.1.1',
warningNodes: [nodeInfo],
incompatibleNodes: [],
// this isn't the real message, just used to test that the message
// is forwarded to the status
message: 'Some nodes are a different version',
})
)
.pipe(take(2))
.toPromise()
).toEqual({
level: ServiceStatusLevels.degraded,
summary: 'Some nodes are a different version',
meta: {
incompatibleNodes: [],
warningNodes: [nodeInfo],
},
});
});
it('changes to critical when isCompatible is false', async () => {
expect(
await calculateStatus$(
of({
isCompatible: false,
kibanaVersion: '2.1.1',
warningNodes: [nodeInfo],
incompatibleNodes: [nodeInfo],
// this isn't the real message, just used to test that the message
// is forwarded to the status
message: 'Incompatible with Elasticsearch',
})
)
.pipe(take(2))
.toPromise()
).toEqual({
level: ServiceStatusLevels.critical,
summary: 'Incompatible with Elasticsearch',
meta: {
incompatibleNodes: [nodeInfo],
warningNodes: [nodeInfo],
},
});
});
it('emits status updates when node compatibility changes', () => {
const nodeCompat$ = new Subject<NodesVersionCompatibility>();
const statusUpdates: ServiceStatus[] = [];
const subscription = calculateStatus$(nodeCompat$).subscribe(status =>
statusUpdates.push(status)
);
nodeCompat$.next({
isCompatible: false,
kibanaVersion: '2.1.1',
incompatibleNodes: [],
warningNodes: [],
message: 'Unable to retrieve version info',
});
nodeCompat$.next({
isCompatible: false,
kibanaVersion: '2.1.1',
incompatibleNodes: [nodeInfo],
warningNodes: [],
message: 'Incompatible with Elasticsearch',
});
nodeCompat$.next({
isCompatible: true,
kibanaVersion: '1.1.1',
warningNodes: [nodeInfo],
incompatibleNodes: [],
message: 'Some nodes are incompatible',
});
nodeCompat$.next({
isCompatible: true,
kibanaVersion: '1.1.1',
warningNodes: [],
incompatibleNodes: [],
});
subscription.unsubscribe();
expect(statusUpdates).toMatchInlineSnapshot(`
Array [
Object {
"level": unavailable,
"meta": Object {
"incompatibleNodes": Array [],
"warningNodes": Array [],
},
"summary": "Waiting for Elasticsearch",
},
Object {
"level": critical,
"meta": Object {
"incompatibleNodes": Array [],
"warningNodes": Array [],
},
"summary": "Unable to retrieve version info",
},
Object {
"level": critical,
"meta": Object {
"incompatibleNodes": Array [
Object {
"http": Object {
"publish_address": "https://1.1.1.1:9200",
},
"ip": "1.1.1.1",
"name": "node1",
"version": "1.1.1",
},
],
"warningNodes": Array [],
},
"summary": "Incompatible with Elasticsearch",
},
Object {
"level": degraded,
"meta": Object {
"incompatibleNodes": Array [],
"warningNodes": Array [
Object {
"http": Object {
"publish_address": "https://1.1.1.1:9200",
},
"ip": "1.1.1.1",
"name": "node1",
"version": "1.1.1",
},
],
},
"summary": "Some nodes are incompatible",
},
Object {
"level": available,
"meta": Object {
"incompatibleNodes": Array [],
"warningNodes": Array [],
},
"summary": "Elasticsearch is available",
},
]
`);
});
});

View file

@ -0,0 +1,78 @@
/*
* 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 { Observable, merge, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { ServiceStatus, ServiceStatusLevels } from '../status';
import { ElasticsearchStatusMeta } from './types';
import { NodesVersionCompatibility } from './version_check/ensure_es_version';
export const calculateStatus$ = (
esNodesCompatibility$: Observable<NodesVersionCompatibility>
): Observable<ServiceStatus<ElasticsearchStatusMeta>> =>
merge(
of({
level: ServiceStatusLevels.unavailable,
summary: `Waiting for Elasticsearch`,
meta: {
warningNodes: [],
incompatibleNodes: [],
},
}),
esNodesCompatibility$.pipe(
map(
({
isCompatible,
message,
incompatibleNodes,
warningNodes,
}): ServiceStatus<ElasticsearchStatusMeta> => {
if (!isCompatible) {
return {
level: ServiceStatusLevels.critical,
summary:
// Message should always be present, but this is a safe fallback
message ??
`Some Elasticsearch nodes are not compatible with this version of Kibana`,
meta: { warningNodes, incompatibleNodes },
};
} else if (warningNodes.length > 0) {
return {
level: ServiceStatusLevels.degraded,
summary:
// Message should always be present, but this is a safe fallback
message ??
`Some Elasticsearch nodes are running different versions than this version of Kibana`,
meta: { warningNodes, incompatibleNodes },
};
}
return {
level: ServiceStatusLevels.available,
summary: `Elasticsearch is available`,
meta: {
warningNodes: [],
incompatibleNodes: [],
},
};
}
)
)
);

View file

@ -22,6 +22,7 @@ import { ElasticsearchConfig } from './elasticsearch_config';
import { ElasticsearchClientConfig } from './elasticsearch_client_config';
import { IClusterClient, ICustomClusterClient } from './cluster_client';
import { NodesVersionCompatibility } from './version_check/ensure_es_version';
import { ServiceStatus } from '../status';
/**
* @public
@ -128,4 +129,11 @@ export interface InternalElasticsearchServiceSetup extends ElasticsearchServiceS
readonly config$: Observable<ElasticsearchConfig>;
};
esNodesCompatibility$: Observable<NodesVersionCompatibility>;
status$: Observable<ServiceStatus<ElasticsearchStatusMeta>>;
}
/** @public */
export interface ElasticsearchStatusMeta {
warningNodes: NodesVersionCompatibility['warningNodes'];
incompatibleNodes: NodesVersionCompatibility['incompatibleNodes'];
}

View file

@ -142,7 +142,7 @@ export const pollEsNodesVersion = ({
kibanaVersion,
ignoreVersionMismatch,
esVersionCheckInterval: healthCheckInterval,
}: PollEsNodesVersionOptions): Observable<any> => {
}: PollEsNodesVersionOptions): Observable<NodesVersionCompatibility> => {
log.debug('Checking Elasticsearch version');
return timer(0, healthCheckInterval).pipe(
exhaustMap(() => {

View file

@ -60,6 +60,7 @@ import {
import { CapabilitiesSetup, CapabilitiesStart } from './capabilities';
import { UuidServiceSetup } from './uuid';
import { MetricsServiceSetup } from './metrics';
import { StatusServiceSetup } from './status';
export { bootstrap } from './bootstrap';
export { Capabilities, CapabilitiesProvider, CapabilitiesSwitcher } from './capabilities';
@ -95,6 +96,8 @@ export {
ElasticsearchErrorHelpers,
ElasticsearchServiceSetup,
ElasticsearchServiceStart,
ElasticsearchStatusMeta,
NodesVersionCompatibility,
APICaller,
FakeRequest,
ScopeableRequest,
@ -226,6 +229,7 @@ export {
SavedObjectsUpdateResponse,
SavedObjectsServiceStart,
SavedObjectsServiceSetup,
SavedObjectStatusMeta,
SavedObjectsDeleteOptions,
ISavedObjectsRepository,
SavedObjectsRepository,
@ -294,6 +298,14 @@ export {
LegacyInternals,
} from './legacy';
export {
CoreStatus,
ServiceStatus,
ServiceStatusLevel,
ServiceStatusLevels,
StatusServiceSetup,
} from './status';
/**
* Plugin specific context passed to a route handler.
*
@ -348,14 +360,16 @@ export interface CoreSetup<TPluginsStart extends object = object, TStart = unkno
elasticsearch: ElasticsearchServiceSetup;
/** {@link HttpServiceSetup} */
http: HttpServiceSetup;
/** {@link MetricsServiceSetup} */
metrics: MetricsServiceSetup;
/** {@link SavedObjectsServiceSetup} */
savedObjects: SavedObjectsServiceSetup;
/** {@link StatusServiceSetup} */
status: StatusServiceSetup;
/** {@link UiSettingsServiceSetup} */
uiSettings: UiSettingsServiceSetup;
/** {@link UuidServiceSetup} */
uuid: UuidServiceSetup;
/** {@link MetricsServiceSetup} */
metrics: MetricsServiceSetup;
/** {@link StartServicesAccessor} */
getStartServices: StartServicesAccessor<TPluginsStart, TStart>;
}

View file

@ -31,6 +31,7 @@ import {
import { InternalUiSettingsServiceSetup, InternalUiSettingsServiceStart } from './ui_settings';
import { UuidServiceSetup } from './uuid';
import { InternalMetricsServiceSetup } from './metrics';
import { InternalStatusServiceSetup } from './status';
/** @internal */
export interface InternalCoreSetup {
@ -38,10 +39,11 @@ export interface InternalCoreSetup {
context: ContextSetup;
http: InternalHttpServiceSetup;
elasticsearch: InternalElasticsearchServiceSetup;
uiSettings: InternalUiSettingsServiceSetup;
savedObjects: InternalSavedObjectsServiceSetup;
uuid: UuidServiceSetup;
metrics: InternalMetricsServiceSetup;
savedObjects: InternalSavedObjectsServiceSetup;
status: InternalStatusServiceSetup;
uiSettings: InternalUiSettingsServiceSetup;
uuid: UuidServiceSetup;
}
/**

View file

@ -48,6 +48,7 @@ import { findLegacyPluginSpecs } from './plugins';
import { LegacyVars, LegacyServiceSetupDeps, LegacyServiceStartDeps } from './types';
import { LegacyService } from './legacy_service';
import { coreMock } from '../mocks';
import { statusServiceMock } from '../status/status_service.mock';
const MockKbnServer: jest.Mock<KbnServer> = KbnServer as any;
@ -106,6 +107,7 @@ beforeEach(() => {
rendering: renderingServiceMock,
metrics: metricsServiceMock.createInternalSetupContract(),
uuid: uuidSetup,
status: statusServiceMock.createInternalSetupContract(),
},
plugins: { 'plugin-id': 'plugin-value' },
};

View file

@ -306,6 +306,9 @@ export class LegacyService implements CoreService {
registerType: setupDeps.core.savedObjects.registerType,
getImportExportObjectLimit: setupDeps.core.savedObjects.getImportExportObjectLimit,
},
status: {
core$: setupDeps.core.status.core$,
},
uiSettings: {
register: setupDeps.core.uiSettings.register,
},

View file

@ -33,6 +33,7 @@ import { InternalCoreSetup, InternalCoreStart } from './internal_types';
import { capabilitiesServiceMock } from './capabilities/capabilities_service.mock';
import { metricsServiceMock } from './metrics/metrics_service.mock';
import { uuidServiceMock } from './uuid/uuid_service.mock';
import { statusServiceMock } from './status/status_service.mock';
export { httpServerMock } from './http/http_server.mocks';
export { sessionStorageMock } from './http/cookie_session_storage.mocks';
@ -133,9 +134,10 @@ function createCoreSetupMock({
elasticsearch: elasticsearchServiceMock.createSetup(),
http: httpMock,
savedObjects: savedObjectsServiceMock.createInternalSetupContract(),
status: statusServiceMock.createSetupContract(),
metrics: metricsServiceMock.createSetupContract(),
uiSettings: uiSettingsMock,
uuid: uuidServiceMock.createSetupContract(),
metrics: metricsServiceMock.createSetupContract(),
getStartServices: jest
.fn<Promise<[ReturnType<typeof createCoreStartMock>, object, any]>, []>()
.mockResolvedValue([createCoreStartMock(), pluginStartDeps, pluginStartContract]),
@ -161,10 +163,11 @@ function createInternalCoreSetupMock() {
context: contextServiceMock.createSetupContract(),
elasticsearch: elasticsearchServiceMock.createInternalSetup(),
http: httpServiceMock.createSetupContract(),
uiSettings: uiSettingsServiceMock.createSetupContract(),
savedObjects: savedObjectsServiceMock.createInternalSetupContract(),
uuid: uuidServiceMock.createSetupContract(),
metrics: metricsServiceMock.createInternalSetupContract(),
savedObjects: savedObjectsServiceMock.createInternalSetupContract(),
status: statusServiceMock.createInternalSetupContract(),
uuid: uuidServiceMock.createSetupContract(),
uiSettings: uiSettingsServiceMock.createSetupContract(),
};
return setupDeps;
}

View file

@ -175,6 +175,9 @@ export function createPluginSetupContext<TPlugin, TPluginDependencies>(
registerType: deps.savedObjects.registerType,
getImportExportObjectLimit: deps.savedObjects.getImportExportObjectLimit,
},
status: {
core$: deps.status.core$,
},
uiSettings: {
register: deps.uiSettings.register,
},

View file

@ -68,7 +68,11 @@ export {
SavedObjectMigrationContext,
} from './migrations';
export { SavedObjectsType, SavedObjectsTypeManagementDefinition } from './types';
export {
SavedObjectStatusMeta,
SavedObjectsType,
SavedObjectsTypeManagementDefinition,
} from './types';
export { savedObjectsConfig, savedObjectsMigrationConfig } from './saved_objects_config';
export { SavedObjectTypeRegistry, ISavedObjectTypeRegistry } from './saved_objects_type_registry';

View file

@ -22,4 +22,4 @@ export { IndexMigrator } from './index_migrator';
export { buildActiveMappings } from './build_active_mappings';
export { CallCluster } from './call_cluster';
export { LogFn } from './migration_logger';
export { MigrationResult } from './migration_coordinator';
export { MigrationResult, MigrationStatus } from './migration_coordinator';

View file

@ -39,6 +39,8 @@ import { SavedObjectsMigrationLogger } from './migration_logger';
const DEFAULT_POLL_INTERVAL = 15000;
export type MigrationStatus = 'waiting' | 'running' | 'completed';
export type MigrationResult =
| { status: 'skipped' }
| { status: 'patched' }

View file

@ -17,6 +17,7 @@
* under the License.
*/
export { MigrationResult } from './core';
export { KibanaMigrator, IKibanaMigrator } from './kibana';
export {
SavedObjectMigrationFn,

View file

@ -17,4 +17,4 @@
* under the License.
*/
export { KibanaMigrator, IKibanaMigrator } from './kibana_migrator';
export { KibanaMigrator, IKibanaMigrator, KibanaMigratorStatus } from './kibana_migrator';

View file

@ -17,10 +17,11 @@
* under the License.
*/
import { KibanaMigrator } from './kibana_migrator';
import { KibanaMigrator, KibanaMigratorStatus } from './kibana_migrator';
import { buildActiveMappings } from '../core';
const { mergeTypes } = jest.requireActual('./kibana_migrator');
import { SavedObjectsType } from '../../types';
import { BehaviorSubject } from 'rxjs';
const defaultSavedObjectTypes: SavedObjectsType[] = [
{
@ -47,6 +48,20 @@ const createMigrator = (
runMigrations: jest.fn(),
getActiveMappings: jest.fn(),
migrateDocument: jest.fn(),
getStatus$: jest.fn(
() =>
new BehaviorSubject<KibanaMigratorStatus>({
status: 'completed',
result: [
{
status: 'migrated',
destIndex: '.test-kibana_2',
sourceIndex: '.test-kibana_1',
elapsedMs: 10,
},
],
})
),
};
mockMigrator.getActiveMappings.mockReturnValue(buildActiveMappings(mergeTypes(types)));

View file

@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { take } from 'rxjs/operators';
import { KibanaMigratorOptions, KibanaMigrator } from './kibana_migrator';
import { loggingServiceMock } from '../../../logging/logging_service.mock';
@ -79,6 +80,33 @@ describe('KibanaMigrator', () => {
.filter(callClusterPath => callClusterPath === 'cat.templates');
expect(callClusterCommands.length).toBe(1);
});
it('emits results on getMigratorResult$()', async () => {
const options = mockOptions();
const clusterStub = jest.fn<any, any>(() => ({ status: 404 }));
options.callCluster = clusterStub;
const migrator = new KibanaMigrator(options);
const migratorStatus = migrator
.getStatus$()
.pipe(take(3))
.toPromise();
await migrator.runMigrations();
const { status, result } = await migratorStatus;
expect(status).toEqual('completed');
expect(result![0]).toMatchObject({
destIndex: '.my-index_1',
elapsedMs: expect.any(Number),
sourceIndex: '.my-index',
status: 'migrated',
});
expect(result![1]).toMatchObject({
destIndex: 'other-index_1',
elapsedMs: expect.any(Number),
sourceIndex: 'other-index',
status: 'migrated',
});
});
});
});

View file

@ -24,10 +24,17 @@
import { Logger } from 'src/core/server/logging';
import { KibanaConfigType } from 'src/core/server/kibana_config';
import { BehaviorSubject } from 'rxjs';
import { IndexMapping, SavedObjectsTypeMappingDefinitions } from '../../mappings';
import { SavedObjectUnsanitizedDoc, SavedObjectsSerializer } from '../../serialization';
import { docValidator, PropertyValidators } from '../../validation';
import { buildActiveMappings, CallCluster, IndexMigrator } from '../core';
import {
buildActiveMappings,
CallCluster,
IndexMigrator,
MigrationResult,
MigrationStatus,
} from '../core';
import { DocumentMigrator, VersionedTransformer } from '../core/document_migrator';
import { createIndexMap } from '../core/build_index_map';
import { SavedObjectsMigrationConfigType } from '../../saved_objects_config';
@ -46,6 +53,11 @@ export interface KibanaMigratorOptions {
export type IKibanaMigrator = Pick<KibanaMigrator, keyof KibanaMigrator>;
export interface KibanaMigratorStatus {
status: MigrationStatus;
result?: MigrationResult[];
}
/**
* Manages the shape of mappings and documents in the Kibana index.
*/
@ -58,7 +70,10 @@ export class KibanaMigrator {
private readonly mappingProperties: SavedObjectsTypeMappingDefinitions;
private readonly typeRegistry: ISavedObjectTypeRegistry;
private readonly serializer: SavedObjectsSerializer;
private migrationResult?: Promise<Array<{ status: string }>>;
private migrationResult?: Promise<MigrationResult[]>;
private readonly status$ = new BehaviorSubject<KibanaMigratorStatus>({
status: 'waiting',
});
/**
* Creates an instance of KibanaMigrator.
@ -109,12 +124,20 @@ export class KibanaMigrator {
Array<{ status: string }>
> {
if (this.migrationResult === undefined || rerun) {
this.migrationResult = this.runMigrationsInternal();
this.status$.next({ status: 'running' });
this.migrationResult = this.runMigrationsInternal().then(result => {
this.status$.next({ status: 'completed', result });
return result;
});
}
return this.migrationResult;
}
public getStatus$() {
return this.status$.asObservable();
}
private runMigrationsInternal() {
const kibanaIndexName = this.kibanaConfig.index;
const indexMap = createIndexMap({

View file

@ -17,6 +17,8 @@
* under the License.
*/
import { BehaviorSubject } from 'rxjs';
import {
SavedObjectsService,
InternalSavedObjectsServiceSetup,
@ -29,6 +31,7 @@ import { savedObjectsClientProviderMock } from './service/lib/scoped_client_prov
import { savedObjectsRepositoryMock } from './service/lib/repository.mock';
import { savedObjectsClientMock } from './service/saved_objects_client.mock';
import { typeRegistryMock } from './saved_objects_type_registry.mock';
import { ServiceStatusLevels } from '../status';
type SavedObjectsServiceContract = PublicMethodsOf<SavedObjectsService>;
@ -75,6 +78,10 @@ const createSetupContractMock = () => {
const createInternalSetupContractMock = () => {
const internalSetupContract: jest.Mocked<InternalSavedObjectsServiceSetup> = {
...createSetupContractMock(),
status$: new BehaviorSubject({
level: ServiceStatusLevels.available,
summary: `SavedObjects is available`,
}),
};
return internalSetupContract;
};

View file

@ -17,8 +17,8 @@
* under the License.
*/
import { Subject } from 'rxjs';
import { first, filter, take } from 'rxjs/operators';
import { Subject, Observable } from 'rxjs';
import { first, filter, take, switchMap } from 'rxjs/operators';
import { CoreService } from '../../types';
import {
SavedObjectsClient,
@ -38,7 +38,7 @@ import {
SavedObjectConfig,
} from './saved_objects_config';
import { KibanaRequest, InternalHttpServiceSetup } from '../http';
import { SavedObjectsClientContract, SavedObjectsType } from './types';
import { SavedObjectsClientContract, SavedObjectsType, SavedObjectStatusMeta } from './types';
import { ISavedObjectsRepository, SavedObjectsRepository } from './service/lib/repository';
import {
SavedObjectsClientFactoryProvider,
@ -50,6 +50,8 @@ import { SavedObjectTypeRegistry, ISavedObjectTypeRegistry } from './saved_objec
import { PropertyValidators } from './validation';
import { SavedObjectsSerializer } from './serialization';
import { registerRoutes } from './routes';
import { ServiceStatus } from '../status';
import { calculateStatus$ } from './status';
/**
* Saved Objects is Kibana's data persistence mechanism allowing plugins to
@ -164,7 +166,9 @@ export interface SavedObjectsServiceSetup {
/**
* @internal
*/
export type InternalSavedObjectsServiceSetup = SavedObjectsServiceSetup;
export interface InternalSavedObjectsServiceSetup extends SavedObjectsServiceSetup {
status$: Observable<ServiceStatus<SavedObjectStatusMeta>>;
}
/**
* Saved Objects is Kibana's data persisentence mechanism allowing plugins to
@ -321,6 +325,10 @@ export class SavedObjectsService
});
return {
status$: calculateStatus$(
this.migrator$.pipe(switchMap(migrator => migrator.getStatus$())),
setupDeps.elasticsearch.status$
),
setClientFactoryProvider: provider => {
if (this.started) {
throw new Error('cannot call `setClientFactoryProvider` after service startup.');

View file

@ -0,0 +1,134 @@
/*
* 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 { of, Observable } from 'rxjs';
import { ServiceStatus, ServiceStatusLevels } from '../status';
import { calculateStatus$ } from './status';
import { take } from 'rxjs/operators';
describe('calculateStatus$', () => {
const expectUnavailableDueToEs = (status$: Observable<ServiceStatus>) =>
expect(status$.pipe(take(1)).toPromise()).resolves.toEqual({
level: ServiceStatusLevels.unavailable,
summary: `SavedObjects service is not available without a healthy Elasticearch connection`,
});
const expectUnavailableDueToMigrations = (status$: Observable<ServiceStatus>) =>
expect(status$.pipe(take(1)).toPromise()).resolves.toEqual({
level: ServiceStatusLevels.unavailable,
summary: `SavedObjects service is waiting to start migrations`,
});
describe('when elasticsearch is unavailable', () => {
const esStatus$ = of<ServiceStatus>({
level: ServiceStatusLevels.unavailable,
summary: 'xxx',
});
it('is unavailable before migrations have ran', async () => {
await expectUnavailableDueToEs(calculateStatus$(of<any>(), esStatus$));
});
it('is unavailable after migrations have ran', async () => {
await expectUnavailableDueToEs(
calculateStatus$(of({ status: 'completed', result: [] }), esStatus$)
);
});
});
describe('when elasticsearch is critical', () => {
const esStatus$ = of<ServiceStatus>({
level: ServiceStatusLevels.critical,
summary: 'xxx',
});
it('is unavailable before migrations have ran', async () => {
await expectUnavailableDueToEs(calculateStatus$(of<any>(), esStatus$));
});
it('is unavailable after migrations have ran', async () => {
await expectUnavailableDueToEs(
calculateStatus$(
of({ status: 'completed', result: [{ status: 'migrated' } as any] }),
esStatus$
)
);
});
});
describe('when elasticsearch is available', () => {
const esStatus$ = of<ServiceStatus>({
level: ServiceStatusLevels.available,
summary: 'Available',
});
it('is unavailable before migrations have ran', async () => {
await expectUnavailableDueToMigrations(calculateStatus$(of<any>(), esStatus$));
});
it('is unavailable while migrations are running', async () => {
await expect(
calculateStatus$(of({ status: 'running' }), esStatus$)
.pipe(take(2))
.toPromise()
).resolves.toEqual({
level: ServiceStatusLevels.unavailable,
summary: `SavedObjects service is running migrations`,
});
});
it('is available after migrations have ran', async () => {
await expect(
calculateStatus$(
of({ status: 'completed', result: [{ status: 'skipped' }, { status: 'patched' }] }),
esStatus$
)
.pipe(take(2))
.toPromise()
).resolves.toEqual({
level: ServiceStatusLevels.available,
summary: `SavedObjects service has completed migrations and is available`,
meta: {
migratedIndices: {
migrated: 0,
patched: 1,
skipped: 1,
},
},
});
});
});
describe('when elasticsearch is degraded', () => {
const esStatus$ = of<ServiceStatus>({ level: ServiceStatusLevels.degraded, summary: 'xxx' });
it('is unavailable before migrations have ran', async () => {
await expectUnavailableDueToMigrations(calculateStatus$(of<any>(), esStatus$));
});
it('is degraded after migrations have ran', async () => {
await expect(
calculateStatus$(
of<any>([{ status: 'skipped' }]),
esStatus$
)
.pipe(take(2))
.toPromise()
).resolves.toEqual({
level: ServiceStatusLevels.degraded,
summary: 'SavedObjects service is degraded due to Elasticsearch: [xxx]',
});
});
});
});

View file

@ -0,0 +1,84 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Observable, combineLatest } from 'rxjs';
import { startWith, map } from 'rxjs/operators';
import { ServiceStatus, ServiceStatusLevels } from '../status';
import { SavedObjectStatusMeta } from './types';
import { KibanaMigratorStatus } from './migrations/kibana';
export const calculateStatus$ = (
rawMigratorStatus$: Observable<KibanaMigratorStatus>,
elasticsearchStatus$: Observable<ServiceStatus>
): Observable<ServiceStatus<SavedObjectStatusMeta>> => {
const migratorStatus$: Observable<ServiceStatus<SavedObjectStatusMeta>> = rawMigratorStatus$.pipe(
map(migrationStatus => {
if (migrationStatus.status === 'waiting') {
return {
level: ServiceStatusLevels.unavailable,
summary: `SavedObjects service is waiting to start migrations`,
};
} else if (migrationStatus.status === 'running') {
return {
level: ServiceStatusLevels.unavailable,
summary: `SavedObjects service is running migrations`,
};
}
const statusCounts: SavedObjectStatusMeta['migratedIndices'] = { migrated: 0, skipped: 0 };
if (migrationStatus.result) {
migrationStatus.result.forEach(({ status }) => {
statusCounts[status] = (statusCounts[status] ?? 0) + 1;
});
}
return {
level: ServiceStatusLevels.available,
summary: `SavedObjects service has completed migrations and is available`,
meta: {
migratedIndices: statusCounts,
},
};
}),
startWith({
level: ServiceStatusLevels.unavailable,
summary: `SavedObjects service is waiting to start migrations`,
})
);
return combineLatest([elasticsearchStatus$, migratorStatus$]).pipe(
map(([esStatus, migratorStatus]) => {
if (esStatus.level >= ServiceStatusLevels.unavailable) {
return {
level: ServiceStatusLevels.unavailable,
summary: `SavedObjects service is not available without a healthy Elasticearch connection`,
};
} else if (migratorStatus.level === ServiceStatusLevels.unavailable) {
return migratorStatus;
} else if (esStatus.level === ServiceStatusLevels.degraded) {
return {
level: esStatus.level,
summary: `SavedObjects service is degraded due to Elasticsearch: [${esStatus.summary}]`,
};
} else {
return migratorStatus;
}
})
);
};

View file

@ -46,6 +46,19 @@ export {
SavedObjectsMigrationVersion,
} from '../../types';
/**
* Meta information about the SavedObjectService's status. Available to plugins via {@link CoreSetup.status}.
*
* @public
*/
export interface SavedObjectStatusMeta {
migratedIndices: {
[status: string]: number;
skipped: number;
migrated: number;
};
}
/**
*
* @public

View file

@ -638,6 +638,8 @@ export interface CoreSetup<TPluginsStart extends object = object, TStart = unkno
// (undocumented)
savedObjects: SavedObjectsServiceSetup;
// (undocumented)
status: StatusServiceSetup;
// (undocumented)
uiSettings: UiSettingsServiceSetup;
// (undocumented)
uuid: UuidServiceSetup;
@ -655,6 +657,14 @@ export interface CoreStart {
uiSettings: UiSettingsServiceStart;
}
// @public
export interface CoreStatus {
// (undocumented)
elasticsearch: ServiceStatus;
// (undocumented)
savedObjects: ServiceStatus;
}
// @public
export class CspConfig implements ICspConfig {
// @internal
@ -794,6 +804,14 @@ export interface ElasticsearchServiceStart {
};
}
// @public (undocumented)
export interface ElasticsearchStatusMeta {
// (undocumented)
incompatibleNodes: NodesVersionCompatibility['incompatibleNodes'];
// (undocumented)
warningNodes: NodesVersionCompatibility['warningNodes'];
}
// @public (undocumented)
export interface EnvironmentMode {
// (undocumented)
@ -1249,6 +1267,24 @@ export type MIGRATION_DEPRECATION_LEVEL = 'none' | 'info' | 'warning' | 'critica
// @public
export type MutatingOperationRefreshSetting = boolean | 'wait_for';
// Warning: (ae-missing-release-tag) "NodesVersionCompatibility" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export interface NodesVersionCompatibility {
// Warning: (ae-forgotten-export) The symbol "NodeInfo" needs to be exported by the entry point index.d.ts
//
// (undocumented)
incompatibleNodes: NodeInfo[];
// (undocumented)
isCompatible: boolean;
// (undocumented)
kibanaVersion: string;
// (undocumented)
message?: string;
// (undocumented)
warningNodes: NodeInfo[];
}
// Warning: (ae-forgotten-export) The symbol "OnPostAuthResult" needs to be exported by the entry point index.d.ts
//
// @public
@ -2169,6 +2205,16 @@ export interface SavedObjectsServiceStart {
getTypeRegistry: () => ISavedObjectTypeRegistry;
}
// @public
export interface SavedObjectStatusMeta {
// (undocumented)
migratedIndices: {
[status: string]: number;
skipped: number;
migrated: number;
};
}
// @public (undocumented)
export interface SavedObjectsType {
convertToAliasScript?: string;
@ -2237,6 +2283,38 @@ export class ScopedClusterClient implements IScopedClusterClient {
callAsInternalUser(endpoint: string, clientParams?: Record<string, any>, options?: CallAPIOptions): Promise<any>;
}
// @public
export interface ServiceStatus<Meta extends Record<string, any> | unknown = unknown> {
detail?: string;
documentationUrl?: string;
level: ServiceStatusLevel;
meta?: Meta;
summary: string;
}
// @public
export type ServiceStatusLevel = typeof ServiceStatusLevels[keyof typeof ServiceStatusLevels];
// @public
export const ServiceStatusLevels: Readonly<{
available: Readonly<{
toString: () => "available";
valueOf: () => 0;
}>;
degraded: Readonly<{
toString: () => "degraded";
valueOf: () => 1;
}>;
unavailable: Readonly<{
toString: () => "unavailable";
valueOf: () => 2;
}>;
critical: Readonly<{
toString: () => "critical";
valueOf: () => 3;
}>;
}>;
// @public
export interface SessionCookieValidationResult {
isValid: boolean;
@ -2274,6 +2352,11 @@ export type SharedGlobalConfig = RecursiveReadonly_2<{
// @public
export type StartServicesAccessor<TPluginsStart extends object = object, TStart = unknown> = () => Promise<[CoreStart, TPluginsStart, TStart]>;
// @public
export interface StatusServiceSetup {
core$: Observable<CoreStatus>;
}
// @public
export type StringValidation = StringValidationRegex | StringValidationRegexString;

View file

@ -85,3 +85,9 @@ export const mockMetricsService = metricsServiceMock.create();
jest.doMock('./metrics/metrics_service', () => ({
MetricsService: jest.fn(() => mockMetricsService),
}));
import { statusServiceMock } from './status/status_service.mock';
export const mockStatusService = statusServiceMock.create();
jest.doMock('./status/status_service', () => ({
StatusService: jest.fn(() => mockStatusService),
}));

View file

@ -29,6 +29,7 @@ import {
mockUiSettingsService,
mockRenderingService,
mockMetricsService,
mockStatusService,
} from './server.test.mocks';
import { BehaviorSubject } from 'rxjs';
@ -63,6 +64,7 @@ test('sets up services on "setup"', async () => {
expect(mockUiSettingsService.setup).not.toHaveBeenCalled();
expect(mockRenderingService.setup).not.toHaveBeenCalled();
expect(mockMetricsService.setup).not.toHaveBeenCalled();
expect(mockStatusService.setup).not.toHaveBeenCalled();
await server.setup();
@ -74,6 +76,7 @@ test('sets up services on "setup"', async () => {
expect(mockUiSettingsService.setup).toHaveBeenCalledTimes(1);
expect(mockRenderingService.setup).toHaveBeenCalledTimes(1);
expect(mockMetricsService.setup).toHaveBeenCalledTimes(1);
expect(mockStatusService.setup).toHaveBeenCalledTimes(1);
});
test('injects legacy dependency to context#setup()', async () => {
@ -141,6 +144,7 @@ test('stops services on "stop"', async () => {
expect(mockSavedObjectsService.stop).not.toHaveBeenCalled();
expect(mockUiSettingsService.stop).not.toHaveBeenCalled();
expect(mockMetricsService.stop).not.toHaveBeenCalled();
expect(mockStatusService.stop).not.toHaveBeenCalled();
await server.stop();
@ -151,6 +155,7 @@ test('stops services on "stop"', async () => {
expect(mockSavedObjectsService.stop).toHaveBeenCalledTimes(1);
expect(mockUiSettingsService.stop).toHaveBeenCalledTimes(1);
expect(mockMetricsService.stop).toHaveBeenCalledTimes(1);
expect(mockStatusService.stop).toHaveBeenCalledTimes(1);
});
test(`doesn't setup core services if config validation fails`, async () => {
@ -167,6 +172,7 @@ test(`doesn't setup core services if config validation fails`, async () => {
expect(mockUiSettingsService.setup).not.toHaveBeenCalled();
expect(mockRenderingService.setup).not.toHaveBeenCalled();
expect(mockMetricsService.setup).not.toHaveBeenCalled();
expect(mockStatusService.setup).not.toHaveBeenCalled();
});
test(`doesn't setup core services if legacy config validation fails`, async () => {
@ -187,4 +193,5 @@ test(`doesn't setup core services if legacy config validation fails`, async () =
expect(mockSavedObjectsService.stop).not.toHaveBeenCalled();
expect(mockUiSettingsService.setup).not.toHaveBeenCalled();
expect(mockMetricsService.setup).not.toHaveBeenCalled();
expect(mockStatusService.setup).not.toHaveBeenCalled();
});

View file

@ -36,6 +36,9 @@ import { UiSettingsService } from './ui_settings';
import { PluginsService, config as pluginsConfig } from './plugins';
import { SavedObjectsService } from '../server/saved_objects';
import { MetricsService, opsConfig } from './metrics';
import { CapabilitiesService } from './capabilities';
import { UuidService } from './uuid';
import { StatusService } from './status/status_service';
import { config as cspConfig } from './csp';
import { config as elasticsearchConfig } from './elasticsearch';
@ -50,8 +53,6 @@ import { mapToObject } from '../utils';
import { ContextService } from './context';
import { RequestHandlerContext } from '.';
import { InternalCoreSetup, InternalCoreStart } from './internal_types';
import { CapabilitiesService } from './capabilities';
import { UuidService } from './uuid';
const coreId = Symbol('core');
const rootConfigPath = '';
@ -70,6 +71,7 @@ export class Server {
private readonly uiSettings: UiSettingsService;
private readonly uuid: UuidService;
private readonly metrics: MetricsService;
private readonly status: StatusService;
private readonly coreApp: CoreApp;
private pluginsInitialized?: boolean;
@ -95,6 +97,7 @@ export class Server {
this.capabilities = new CapabilitiesService(core);
this.uuid = new UuidService(core);
this.metrics = new MetricsService(core);
this.status = new StatusService(core);
this.coreApp = new CoreApp(core);
}
@ -145,15 +148,21 @@ export class Server {
const metricsSetup = await this.metrics.setup({ http: httpSetup });
const statusSetup = this.status.setup({
elasticsearch: elasticsearchServiceSetup,
savedObjects: savedObjectsSetup,
});
const coreSetup: InternalCoreSetup = {
capabilities: capabilitiesSetup,
context: contextServiceSetup,
elasticsearch: elasticsearchServiceSetup,
http: httpSetup,
uiSettings: uiSettingsSetup,
savedObjects: savedObjectsSetup,
uuid: uuidSetup,
metrics: metricsSetup,
savedObjects: savedObjectsSetup,
status: statusSetup,
uiSettings: uiSettingsSetup,
uuid: uuidSetup,
};
const pluginsSetup = await this.plugins.setup(coreSetup);
@ -220,6 +229,7 @@ export class Server {
await this.uiSettings.stop();
await this.rendering.stop();
await this.metrics.stop();
await this.status.stop();
}
private registerCoreContext(coreSetup: InternalCoreSetup, rendering: RenderingServiceSetup) {

Some files were not shown because too many files have changed in this diff Show more