Merge branch '8.7' into risk_score_api_8.7

* 8.7: (93 commits)
  [8.7] [Controls] Use EUI Selectable for Field search (#151231) (#155454)
  [8.7] [Synthetics] Fix  performance breakdown link from error details page (#155393) (#155427)
  [8.7] [DOCS] Remove or move book-scoped attributes (#155210) (#155426)
  [8.7] [Synthetics] add default email recovery message (#154862) (#155418)
  [8.7] [Uptime] Add both both ip filters for view host in uptime location for host and monitor (#155382) (#155399)
  [8.7] Setup Node.js environment before instrumenting Kibana with APM. (#155063) (#155300)
  [8.7] [Discover] Address react warnings for legacy table (#154579) (#155345)
  [8.7] [Fleet] Fix logs useless rerender (#155305) (#155310)
  [8.7] [kbn-failed-test-reporter-cli] truncate report message to fix github api call failure (#155141) (#155286)
  [8.7][APM] Fleet migration support for bundled APM package (#153159)  (#155281)
  [8.7] [Enterprise Search] Fix Connector scheduling show week information correctly (#155191) (#155227)
  [8.7] [Synthetics] Fix pending count in case of location filtering (#155200) (#155225)
  [8.7] [Controls] Add Expensive Queries Fallback (#155082) (#155189)
  [8.7] [data view field editor] Runtime field code editor - move state out of controller (#155107) (#155150)
  [8.7] [FullStory] Update snippet (#153570) (#155138)
  [8.7] [Security Solution][Exceptions] - Fix exception operator logic when mapping conflict (#155071) (#155094)
  [DOCS] Adds 8.7.1 release notes (#154844)
  [8.7] Sync bundled packages with Package Storage (#155042)
  [APM] plugin description (#154811)
  Update api.asciidoc (#155021)
  ...
This commit is contained in:
Ryland Herrick 2023-04-21 09:51:22 -05:00
commit c70c7ea9e6
383 changed files with 6273 additions and 4226 deletions

View file

@ -176,6 +176,7 @@ enabled:
- x-pack/test/api_integration/apis/uptime/config.ts
- x-pack/test/api_integration/apis/watcher/config.ts
- x-pack/test/apm_api_integration/basic/config.ts
- x-pack/test/apm_api_integration/cloud/config.ts
- x-pack/test/apm_api_integration/rules/config.ts
- x-pack/test/apm_api_integration/trial/config.ts
- x-pack/test/banners_functional/config.ts

View file

@ -0,0 +1,6 @@
steps:
- command: .buildkite/scripts/steps/artifacts/trigger.sh
label: Trigger artifacts build
agents:
queue: kibana-default
timeout_in_minutes: 10

View file

@ -23,9 +23,16 @@ else
WORKFLOW="snapshot"
fi
ARTIFACTS_SUBDOMAIN="artifacts-$WORKFLOW"
ARTIFACTS_MANIFEST_FQDN="https://$ARTIFACTS_SUBDOMAIN.elastic.co"
KIBANA_MANIFEST_LATEST="$ARTIFACTS_MANIFEST_FQDN/kibana/latest/$FULL_VERSION.json"
BEATS_MANIFEST_LATEST="$ARTIFACTS_MANIFEST_FQDN/beats/latest/$FULL_VERSION.json"
export VERSION_QUALIFIER
export BASE_VERSION
export QUALIFIER_VERSION
export FULL_VERSION
export BUILD_ARGS
export WORKFLOW
export KIBANA_MANIFEST_LATEST
export BEATS_MANIFEST_LATEST

View file

@ -79,13 +79,12 @@ if [[ "$BUILDKITE_BRANCH" == "$KIBANA_BASE_BRANCH" ]]; then
--dependency "beats:$BEATS_MANIFEST_URL" \
--artifact-set main
ARTIFACTS_SUBDOMAIN="artifacts-$WORKFLOW"
ARTIFACTS_SUMMARY=$(curl -s "https://$ARTIFACTS_SUBDOMAIN.elastic.co/kibana/latest/$FULL_VERSION.json" | jq -re '.summary_url')
KIBANA_SUMMARY=$(curl -s "$KIBANA_MANIFEST_LATEST" | jq -re '.summary_url')
cat << EOF | buildkite-agent annotate --style "info" --context artifacts-summary
### Artifacts Summary
$ARTIFACTS_SUMMARY
$KIBANA_SUMMARY
EOF
else

View file

@ -0,0 +1,20 @@
#!/bin/bash
set -euo pipefail
source .buildkite/scripts/steps/artifacts/env.sh
BEATS_MANIFEST_LATEST_URL=$(curl "$BEATS_MANIFEST_LATEST" | jq -r '.manifest_url')
KIBANA_MANIFEST_URL=$(curl "$KIBANA_MANIFEST_LATEST" | jq -r '.manifest_url')
KIBANA_BEATS_MANIFEST_URL=$(curl $KIBANA_MANIFEST_URL | jq -r '.projects.kibana.dependencies[] | select(.prefix == "beats") | .build_uri')
echo "--- Trigger artifact builds"
if [ "$BEATS_MANIFEST_LATEST_URL" = "$KIBANA_BEATS_MANIFEST_URL" ]; then
echo "Kibana has the latest version of beats, skipping trigger"
else
# Staging builds are not necessary on main
if [[ "$BUILDKITE_BRANCH" != "main" ]]; then
ts-node .buildkite/scripts/steps/trigger_pipeline.ts kibana-artifacts-staging "$BUILDKITE_BRANCH"
fi
ts-node .buildkite/scripts/steps/trigger_pipeline.ts kibana-artifacts-snapshot "$BUILDKITE_BRANCH"
fi

View file

@ -257,8 +257,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---
This code is part of the Services provided by FullStory, Inc. For license information, please refer to https://www.fullstory.com/legal/terms-and-conditions/.
Portions of this code are licensed separately and can be found in https://edge.fullstory.com/s/fs.js.LICENSE.txt
This code is part of the Services provided by FullStory, Inc. For license information, please refer to https://www.fullstory.com/legal/terms-and-conditions/
Portions of this code are licensed under the following license:
For license information please see fs.js.LICENSE.txt
---
This product bundles bootstrap@3.3.6 which is available under a

View file

@ -8,8 +8,9 @@
:issue: https://github.com/elastic/kibana/issues/
:pull: https://github.com/elastic/kibana/pull/
Review important information about the {kib} 8.7.0 release.
Review important information about the {kib} 8.7.x releases.
* <<release-notes-8.7.1>>
* <<release-notes-8.7.0>>
//* <<release-notes-8.6.1>>
//* <<release-notes-8.6.0>>
@ -40,14 +41,101 @@ Review important information about the {kib} 8.7.0 release.
//* <<release-notes-8.0.0-alpha2>>
//* <<release-notes-8.0.0-alpha1>>
--
[[release-notes-8.7.1]]
== {kib} 8.7.1
coming::[8.7.1]
Review the following information about the {kib} 8.7.1 release.
[float]
[[breaking-changes-8.7.1]]
=== Breaking changes
Breaking changes can prevent your application from optimal operation and performance.
Before you upgrade to 8.7.1, review the breaking changes, then mitigate the impact to your application.
// tag::notable-breaking-changes[]
There are no breaking changes in the {kib} 8.7.1 release.
// end::notable-breaking-changes[]
To review the breaking changes in the previous release, check {kibana-ref-all}/8.7/release-notes-8.7.0.html#breaking-changes-8.7.0[8.7.0].
[float]
[[enhancement-v8.7.1]]
=== Enhancement
Fleet::
The agent policy "Host name format" selector is now enabled by default {kibana-pull}154563[#154563]
[float]
[[fixes-v8.7.1]]
=== Bug fixes
APM::
* Scoring is now applied by ES {kibana-pull}154627[#154627]
* Fixes the APM Java Agent download link {kibana-pull}154023[#154023]
* Improves the overflow message text {kibana-pull}153676[#153676]
Canvas::
* Disables the Edit in Lens action for the legacy savedVisualization function {kibana-pull}154656[#154656]
* Fixes the home page redirect loop {kibana-pull}154568[#154568]
* Fixes an issue where the image upload component was unable to load for image elements {kibana-pull}154385[#154385]
Dashboard::
Improves controls flyout performance for data views with a large number of fields {kibana-pull}154004[#154004]
Discover::
Fixes aborted request handling in the saved search embeddable {kibana-pull}153822[#153822]
Elastic Security::
For the Elastic Security 8.7.1 release information, refer to {security-guide}/release-notes.html[_Elastic Security Solution Release Notes_].
Fleet::
* Fixes an issue where the Advanced options toggle in the policy editor was always showing {kibana-pull}154612[#154612]
* Fixes an issue where the warning icon was unable to display in 8.7 {kibana-pull}154119[#154119]
* Adds updates to output logic {kibana-pull}153226[#153226]
Infrastructure::
Fixes the inventory table pagination navigation {kibana-pull}153849[#153849]
Lens & Visualizations::
Fixes the timezone that *Lens* uses in normalize by unit {kibana-pull}154472[#154472]
Machine Learning::
* Change point detection: Fixes applied filters and queries to the charts {kibana-pull}154707[#154707]
* Change point detection: Fixes support for running over relative time range {kibana-pull}154313[#154313]
* Reinstates cold and frozen tier filters for Linux and Windows security modules {kibana-pull}153222[#153222]
Maps::
Fixes an issue where geographic filters were unable to work when courier:ignoreFilterIfFieldNotInIndex was enabled {kibana-pull}153816[#153816]
Monitoring::
Fixes the CCR read_exceptions alert {kibana-pull}153888[#153888]
Querying & Filtering::
Fixes the ability to copy and paste the comma delimeter for multifields {kibana-pull}153772[#153772]
[[release-notes-8.7.0]]
== {kib} 8.7.0
coming::[8.7.0]
Review the following information about the {kib} 8.7.0 release.
[float]
[[known-issues-8.7.0]]
=== Known issues
// tag::known-issue-151698[]
[discrete]
.Observability Overview shows empty User Experience panel
[%collapsible]
====
*Details* +
Release 8.7.0 has a bug causing the Observability Overview page to show an empty User Experience panel, even when there is RUM data (fixed in {kibana-pull}154419[#154419]).
*Impact* +
While the User Experience panel on the Observability Overview page is empty, any RUM data will still be available from the User Experience Dashboard.
====
// end::known-issue-151698[]
[float]
[[breaking-changes-8.7.0]]
=== Breaking changes
@ -187,7 +275,8 @@ Machine Learning::
* Anomaly Detection wizards: adds geo job wizard {kibana-pull}147043[#147043]
Management::
Adds field statistics popovers for Data Frame Analytics & Transform creation wizards {kibana-pull}149879[#149879]
* Adds field statistics popovers for Data Frame Analytics & Transform creation wizards {kibana-pull}149879[#149879]
* Transforms: Shows health status of transform in UI {kibana-pull}150359[#150359]
Monitoring::
* Adds duration configuration to Stack Monitoring Cluster Health rule {kibana-pull}147565[#147565]
@ -319,7 +408,6 @@ Machine Learning::
* Remove beta badge for Field statistics table in Discover {kibana-pull}140991[#140991]
Management::
* Transforms: Health status information in transform list {kibana-pull}150359[#150359]
* Transforms: Adds "Use full data" button to transform creation wizard {kibana-pull}150030[#150030]
* Adds override field to Dot expander processor form {kibana-pull}149599[#149599]
* Adds fields to Append Ingest Pipeline processor form {kibana-pull}149520[#149520]
@ -4836,4 +4924,4 @@ The 8.0.0-alpha1 release includes the following bug fix.
Operations::
* Moves systemd service to /usr/lib/systemd/system {kibana-pull}83571[#83571]
//////////////////
//////////////////

View file

@ -98,7 +98,7 @@ Any modifications made to this file will be overwritten.
<a href="#connector_response_properties">connector_response_properties</a>
<h4 class="field-label">401</h4>
Authorization information is missing or invalid.
<a href="#401_response">401_response</a>
<a href="#Unauthorized_response">Unauthorized_response</a>
</div> <!-- method -->
<hr/>
<div class="method"><a name="deleteConnector"/>
@ -146,7 +146,7 @@ Any modifications made to this file will be overwritten.
<a href="#"></a>
<h4 class="field-label">401</h4>
Authorization information is missing or invalid.
<a href="#401_response">401_response</a>
<a href="#Unauthorized_response">Unauthorized_response</a>
<h4 class="field-label">404</h4>
Object is not found.
<a href="#getConnector_404_response">getConnector_404_response</a>
@ -198,7 +198,7 @@ Any modifications made to this file will be overwritten.
<a href="#connector_response_properties">connector_response_properties</a>
<h4 class="field-label">401</h4>
Authorization information is missing or invalid.
<a href="#401_response">401_response</a>
<a href="#Unauthorized_response">Unauthorized_response</a>
<h4 class="field-label">404</h4>
Object is not found.
<a href="#getConnector_404_response">getConnector_404_response</a>
@ -262,7 +262,7 @@ Any modifications made to this file will be overwritten.
<h4 class="field-label">401</h4>
Authorization information is missing or invalid.
<a href="#401_response">401_response</a>
<a href="#Unauthorized_response">Unauthorized_response</a>
</div> <!-- method -->
<hr/>
<div class="method"><a name="getConnectors"/>
@ -320,7 +320,7 @@ Any modifications made to this file will be overwritten.
<h4 class="field-label">401</h4>
Authorization information is missing or invalid.
<a href="#401_response">401_response</a>
<a href="#Unauthorized_response">Unauthorized_response</a>
</div> <!-- method -->
<hr/>
<div class="method"><a name="legacyCreateConnector"/>
@ -394,7 +394,7 @@ Any modifications made to this file will be overwritten.
<a href="#action_response_properties">action_response_properties</a>
<h4 class="field-label">401</h4>
Authorization information is missing or invalid.
<a href="#401_response">401_response</a>
<a href="#Unauthorized_response">Unauthorized_response</a>
</div> <!-- method -->
<hr/>
<div class="method"><a name="legacyDeleteConnector"/>
@ -442,7 +442,7 @@ Any modifications made to this file will be overwritten.
<a href="#"></a>
<h4 class="field-label">401</h4>
Authorization information is missing or invalid.
<a href="#401_response">401_response</a>
<a href="#Unauthorized_response">Unauthorized_response</a>
</div> <!-- method -->
<hr/>
<div class="method"><a name="legacyGetConnector"/>
@ -499,7 +499,7 @@ Any modifications made to this file will be overwritten.
<a href="#action_response_properties">action_response_properties</a>
<h4 class="field-label">401</h4>
Authorization information is missing or invalid.
<a href="#401_response">401_response</a>
<a href="#Unauthorized_response">Unauthorized_response</a>
</div> <!-- method -->
<hr/>
<div class="method"><a name="legacyGetConnectorTypes"/>
@ -553,7 +553,7 @@ Any modifications made to this file will be overwritten.
<h4 class="field-label">401</h4>
Authorization information is missing or invalid.
<a href="#401_response">401_response</a>
<a href="#Unauthorized_response">Unauthorized_response</a>
</div> <!-- method -->
<hr/>
<div class="method"><a name="legacyGetConnectors"/>
@ -608,7 +608,7 @@ Any modifications made to this file will be overwritten.
<h4 class="field-label">401</h4>
Authorization information is missing or invalid.
<a href="#401_response">401_response</a>
<a href="#Unauthorized_response">Unauthorized_response</a>
</div> <!-- method -->
<hr/>
<div class="method"><a name="legacyRunConnector"/>
@ -679,7 +679,7 @@ Any modifications made to this file will be overwritten.
<a href="#legacyRunConnector_200_response">legacyRunConnector_200_response</a>
<h4 class="field-label">401</h4>
Authorization information is missing or invalid.
<a href="#401_response">401_response</a>
<a href="#Unauthorized_response">Unauthorized_response</a>
</div> <!-- method -->
<hr/>
<div class="method"><a name="legacyUpdateConnector"/>
@ -755,7 +755,7 @@ Any modifications made to this file will be overwritten.
<a href="#action_response_properties">action_response_properties</a>
<h4 class="field-label">404</h4>
Object is not found.
<a href="#404_response">404_response</a>
<a href="#Not_found_response">Not_found_response</a>
</div> <!-- method -->
<hr/>
<div class="method"><a name="runConnector"/>
@ -826,7 +826,7 @@ Any modifications made to this file will be overwritten.
<a href="#runConnector_200_response">runConnector_200_response</a>
<h4 class="field-label">401</h4>
Authorization information is missing or invalid.
<a href="#401_response">401_response</a>
<a href="#Unauthorized_response">Unauthorized_response</a>
</div> <!-- method -->
<hr/>
<div class="method"><a name="updateConnector"/>
@ -897,10 +897,10 @@ Any modifications made to this file will be overwritten.
<a href="#updateConnector_400_response">updateConnector_400_response</a>
<h4 class="field-label">401</h4>
Authorization information is missing or invalid.
<a href="#401_response">401_response</a>
<a href="#Unauthorized_response">Unauthorized_response</a>
<h4 class="field-label">404</h4>
Object is not found.
<a href="#404_response">404_response</a>
<a href="#Not_found_response">Not_found_response</a>
</div> <!-- method -->
<hr/>
@ -909,8 +909,6 @@ Any modifications made to this file will be overwritten.
<h3>Table of Contents</h3>
<ol>
<li><a href="#401_response"><code>401_response</code> - Unsuccessful rule API response</a></li>
<li><a href="#404_response"><code>404_response</code> - </a></li>
<li><a href="#Alert_identifier_mapping"><code>Alert_identifier_mapping</code> - Alert identifier mapping</a></li>
<li><a href="#Case_comment_mapping"><code>Case_comment_mapping</code> - Case comment mapping</a></li>
<li><a href="#Case_description_mapping"><code>Case_description_mapping</code> - Case description mapping</a></li>
@ -924,11 +922,13 @@ Any modifications made to this file will be overwritten.
<li><a href="#Legacy_get_connector_types_response_body_properties_inner"><code>Legacy_get_connector_types_response_body_properties_inner</code> - </a></li>
<li><a href="#Legacy_run_connector_request_body_properties"><code>Legacy_run_connector_request_body_properties</code> - Legacy run connector request body properties</a></li>
<li><a href="#Legacy_update_connector_request_body_properties"><code>Legacy_update_connector_request_body_properties</code> - Legacy update connector request body properties</a></li>
<li><a href="#Not_found_response"><code>Not_found_response</code> - Not found response</a></li>
<li><a href="#Rule_name_mapping"><code>Rule_name_mapping</code> - Rule name mapping</a></li>
<li><a href="#Run_connector_request_body_properties"><code>Run_connector_request_body_properties</code> - Run connector request body properties</a></li>
<li><a href="#Run_connector_request_body_properties_params"><code>Run_connector_request_body_properties_params</code> - </a></li>
<li><a href="#Severity_mapping"><code>Severity_mapping</code> - Severity mapping</a></li>
<li><a href="#Subaction_parameters"><code>Subaction_parameters</code> - Subaction parameters</a></li>
<li><a href="#Unauthorized_response"><code>Unauthorized_response</code> - Unauthorized response</a></li>
<li><a href="#Update_connector_request_body_properties"><code>Update_connector_request_body_properties</code> - Update connector request body properties</a></li>
<li><a href="#action_response_properties"><code>action_response_properties</code> - Action response properties</a></li>
<li><a href="#config_properties_cases_webhook"><code>config_properties_cases_webhook</code> - Connector request properties for Webhook - Case Management connector</a></li>
@ -1028,32 +1028,6 @@ Any modifications made to this file will be overwritten.
<li><a href="#update_connector_request_swimlane"><code>update_connector_request_swimlane</code> - Update Swimlane connector request</a></li>
</ol>
<div class="model">
<h3><a name="401_response"><code>401_response</code> - Unsuccessful rule API response</a> <a class="up" href="#__Models">Up</a></h3>
<div class='model-description'></div>
<div class="field-items">
<div class="param">error (optional)</div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
<div class="param-enum-header">Enum:</div>
<div class="param-enum">Unauthorized</div>
<div class="param">message (optional)</div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
<div class="param">statusCode (optional)</div><div class="param-desc"><span class="param-type"><a href="#integer">Integer</a></span> </div>
<div class="param-enum-header">Enum:</div>
<div class="param-enum">401</div>
</div> <!-- field-items -->
</div>
<div class="model">
<h3><a name="404_response"><code>404_response</code> - </a> <a class="up" href="#__Models">Up</a></h3>
<div class='model-description'></div>
<div class="field-items">
<div class="param">error (optional)</div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
<div class="param-enum-header">Enum:</div>
<div class="param-enum">Not Found</div>
<div class="param">message (optional)</div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
<div class="param">statusCode (optional)</div><div class="param-desc"><span class="param-type"><a href="#integer">Integer</a></span> </div>
<div class="param-enum-header">Enum:</div>
<div class="param-enum">404</div>
</div> <!-- field-items -->
</div>
<div class="model">
<h3><a name="Alert_identifier_mapping"><code>Alert_identifier_mapping</code> - Alert identifier mapping</a> <a class="up" href="#__Models">Up</a></h3>
<div class='model-description'>Mapping for the alert ID.</div>
@ -1194,6 +1168,19 @@ Any modifications made to this file will be overwritten.
<div class="param">secrets (optional)</div><div class="param-desc"><span class="param-type"><a href="#">Object</a></span> The updated secrets configuration for the connector. Secrets properties vary depending on the connector type. </div>
</div> <!-- field-items -->
</div>
<div class="model">
<h3><a name="Not_found_response"><code>Not_found_response</code> - Not found response</a> <a class="up" href="#__Models">Up</a></h3>
<div class='model-description'></div>
<div class="field-items">
<div class="param">error (optional)</div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
<div class="param-enum-header">Enum:</div>
<div class="param-enum">Not Found</div>
<div class="param">message (optional)</div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
<div class="param">statusCode (optional)</div><div class="param-desc"><span class="param-type"><a href="#integer">Integer</a></span> </div>
<div class="param-enum-header">Enum:</div>
<div class="param-enum">404</div>
</div> <!-- field-items -->
</div>
<div class="model">
<h3><a name="Rule_name_mapping"><code>Rule_name_mapping</code> - Rule name mapping</a> <a class="up" href="#__Models">Up</a></h3>
<div class='model-description'>Mapping for the name of the alert's rule.</div>
@ -1246,6 +1233,19 @@ Any modifications made to this file will be overwritten.
<div class="param">subActionParams </div><div class="param-desc"><span class="param-type"><a href="#run_connector_subaction_pushtoservice_subActionParams">run_connector_subaction_pushtoservice_subActionParams</a></span> </div>
</div> <!-- field-items -->
</div>
<div class="model">
<h3><a name="Unauthorized_response"><code>Unauthorized_response</code> - Unauthorized response</a> <a class="up" href="#__Models">Up</a></h3>
<div class='model-description'></div>
<div class="field-items">
<div class="param">error (optional)</div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
<div class="param-enum-header">Enum:</div>
<div class="param-enum">Unauthorized</div>
<div class="param">message (optional)</div><div class="param-desc"><span class="param-type"><a href="#string">String</a></span> </div>
<div class="param">statusCode (optional)</div><div class="param-desc"><span class="param-type"><a href="#integer">Integer</a></span> </div>
<div class="param-enum-header">Enum:</div>
<div class="param-enum">401</div>
</div> <!-- field-items -->
</div>
<div class="model">
<h3><a name="Update_connector_request_body_properties"><code>Update_connector_request_body_properties</code> - Update connector request body properties</a> <a class="up" href="#__Models">Up</a></h3>
<div class='model-description'>The properties vary depending on the connector type.</div>

View file

@ -62,7 +62,7 @@ Update a title of the `<my-view>` data view:
[source,sh]
--------------------------------------------------
$ curl -X POST api/data_views/data-view/my-view
$ curl -X POST api/data_views/data_view/my-view
{
"data_view": {
"title": "some-other-view-*"
@ -75,7 +75,7 @@ Customize the update behavior:
[source,sh]
--------------------------------------------------
$ curl -X POST api/data_views/data-view/my-view
$ curl -X POST api/data_views/data_view/my-view
{
"refresh_fields": true,
"data_view": {
@ -90,7 +90,7 @@ All update fields are optional, but you can specify the following fields:
[source,sh]
--------------------------------------------------
$ curl -X POST api/data_views/data-view/my-view
$ curl -X POST api/data_views/data_view/my-view
{
"data_view": {
"title": "...",

View file

@ -6,11 +6,11 @@
<titleabbrev>Configure APM agents with central config</titleabbrev>
++++
APM Agent configuration allows you to fine-tune your agent configuration from within the APM app.
APM Agent configuration allows you to fine-tune your APM agent configuration from within the APM app.
Changes are automatically propagated to your APM agents, so there's no need to redeploy.
To get started, choose the services and environments you wish to configure.
The APM app will let you know when your agents have applied your configurations.
The APM app will let you know when your APM agents have applied your configurations.
[role="screenshot"]
image::apm/images/apm-agent-configuration.png[APM Agent configuration in Kibana]
@ -18,28 +18,39 @@ image::apm/images/apm-agent-configuration.png[APM Agent configuration in Kibana]
[float]
==== Precedence
Configurations set from the APM app take precedence over configurations set locally in each Agent.
Configurations set from the APM app take precedence over configurations set locally in each APM agent.
However, if APM Server is slow to respond, is offline, reports an error, etc.,
APM agents will use local defaults until they're able to update the configuration.
For this reason, it is still essential to set custom default configurations locally in each of your agents.
For this reason, it is still essential to set custom default configurations locally in each of your APM agents.
[float]
==== Supported configurations
Each Agent has a list of supported configurations.
Each APM agent has a list of supported configurations.
After selecting a Service name and environment in the APM app,
a list of all supported configuration options,
including descriptions and default values, will be displayed.
Supported configurations are also tagged with the image:./images/dynamic-config.svg[] badge in each Agent's configuration reference:
Supported configurations are also tagged with the image:./images/dynamic-config.svg[] badge in each APM agent's configuration reference:
[horizontal]
Go Agent:: {apm-go-ref}/configuration.html[Configuration reference]
Android agent:: {apm-android-ref}/configuration.html[Configuration reference]
Go agent:: {apm-go-ref}/configuration.html[Configuration reference]
iOS agent:: _Not yet supported_
Java Agent:: {apm-java-ref}/configuration.html[Configuration reference]
.NET Agent:: {apm-dotnet-ref}/configuration.html[Configuration reference]
Node.js Agent:: {apm-node-ref}/configuration.html[Configuration reference]
PHP Agent:: {apm-php-ref}/configuration.html[Configuration reference]
Python Agent:: {apm-py-ref}/configuration.html[Configuration reference]
Ruby Agent:: {apm-ruby-ref}/configuration.html[Configuration reference]
Real User Monitoring (RUM) Agent:: {apm-rum-ref}/configuration.html[Configuration reference]
Java agent:: {apm-java-ref}/configuration.html[Configuration reference]
.NET agent:: {apm-dotnet-ref}/configuration.html[Configuration reference]
Node.js agent:: {apm-node-ref}/configuration.html[Configuration reference]
PHP agent:: {apm-php-ref}/configuration.html[Configuration reference]
Python agent:: {apm-py-ref}/configuration.html[Configuration reference]
Ruby agent:: {apm-ruby-ref}/configuration.html[Configuration reference]
Real User Monitoring (RUM) agent:: {apm-rum-ref}/configuration.html[Configuration reference]
[float]
==== APM Server configuration
For most users, APM agent configuration should work out-of-the-box.
If you run into trouble, it may be because you're not using the {es} output,
or because your {es} credentials don't have sufficient privileges.
See {apm-guide-ref}/configure-agent-config.html[configure APM agent configuration]
to learn how to configure APM Server to avoid these problems.

View file

@ -87,15 +87,15 @@ which you can use to automate certain aspects of configuring and deploying Kiban
[[agent-config-api]]
=== Agent Configuration API
The Agent configuration API allows you to fine-tune your APM agent configuration,
The APM agent configuration API allows you to fine-tune your APM agent configuration,
without needing to redeploy your application.
The following Agent configuration APIs are available:
The following APM agent configuration APIs are available:
* <<apm-update-config>> to create or update an Agent configuration
* <<apm-delete-config>> to delete an Agent configuration.
* <<apm-list-config>> to list all Agent configurations.
* <<apm-search-config>> to search for an Agent configuration.
* <<apm-update-config>> to create or update an APM agent configuration
* <<apm-delete-config>> to delete an APM agent configuration.
* <<apm-list-config>> to list all APM agent configurations.
* <<apm-search-config>> to search for an APM agent configuration.
[float]
[[use-agent-config-api]]
@ -307,7 +307,7 @@ GET /api/apm/settings/agent-configuration
======
`etag`::
(required) etag is sent by the agent to indicate the etag of the last successfully applied configuration. If the etag matches an existing configuration its `applied_by_agent` property will be set to `true`. Every time a configuration is edited `applied_by_agent` is reset to `false`.
(required) etag is sent by the APM agent to indicate the etag of the last successfully applied configuration. If the etag matches an existing configuration its `applied_by_agent` property will be set to `true`. Every time a configuration is edited `applied_by_agent` is reset to `false`.
[[apm-search-config-body]]
===== Response body
@ -719,11 +719,11 @@ curl -X DELETE "http://localhost:5601/api/apm/sourcemaps/apm:foo-1.0.0-644fd5a9"
[[agent-key-api]]
=== APM agent Key API
The Agent Key API allows you to configure agent keys to authorize requests from APM agents to the APM Server.
The APM agent Key API allows you to configure APM agent keys to authorize requests from APM agents to the APM Server.
The following Agent key APIs are available:
The following APM agent key APIs are available:
* <<apm-create-agent-key>> to create an agent key
* <<apm-create-agent-key>> to create an APM agent key
[float]
[[use-agent-key-api]]
@ -778,13 +778,13 @@ POST /_security/role/apm_agent_key_user
===== Request body
`name`::
(required, string) Name of the agent key.
(required, string) Name of the APM agent key.
`privileges`::
(required, array) APM agent key privileges. It can take one or more of the following values:
- `event:write`. Required for ingesting agent events.
- `config_agent:read`. Required for agents to read agent configuration remotely.
- `event:write`. Required for ingesting APM agent events.
- `config_agent:read`. Required for APM agents to read agent configuration remotely.
[[apm-agent-key-create-example]]
===== Example

View file

@ -175,7 +175,7 @@ See <<apm-app-api-user>>.
[[apm-app-central-config-manager]]
==== Central configuration manager
Central configuration users need to be able to view, create, update, and delete Agent configurations.
Central configuration users need to be able to view, create, update, and delete APM agent configurations.
. Create a new role, named something like `central-config-manager`, and assign the following privileges:
+

View file

@ -20,14 +20,16 @@ Selecting an error group ID or error message brings you to the *Error group*.
[role="screenshot"]
image::apm/images/apm-error-group.png[APM Error group]
Here, you'll see the error message, culprit, and the number of occurrences over time.
The error group details page visualizes the number of error occurrences over time and compared to a recent time range.
This allows you to quickly determine if the error rate is changing or remaining constant.
You'll also see the top 5 affected transactions--enabling you to quickly narrow down which transactions are most impacted
by the selected error.
Further down, you'll see the Error occurrence table.
This table shows the details of a sampled error within this group.
Further down, you'll see an Error sample.
The error shown is always the most recent to occur.
The sample includes the exception message, culprit, stack trace where the error occurred,
and additional contextual information to help debug the issue--all of which can be copied with the click of a button.
Each error occurrence features a breakdown of the exception, including the stack trace from when the error occurred,
and additional contextual information to help debug the issue.
In some cases, you might also see a Transaction sample ID.
This feature allows you to make a connection between the errors and transactions,
by linking you to the specific transaction where the error occurred.

View file

@ -32,8 +32,8 @@ It allows you to view only relevant data and is especially useful for separating
By default, all environments are displayed. If there are no environment options, you'll see "not defined".
Service environments are defined when configuring your APM agents.
It's vital to be consistent when naming environments in your agents.
To learn how to configure service environments, see the specific agent documentation:
It's vital to be consistent when naming environments in your APM agents.
To learn how to configure service environments, see the specific APM agent documentation:
* *Go:* {apm-go-ref}/configuration.html#config-environment[`ELASTIC_APM_ENVIRONMENT`]
* *iOS agent:* _Not yet supported_

View file

@ -35,6 +35,7 @@ start with:
Notice something awry? Select a service or trace and dive deeper with:
* <<service-overview>>
* <<mobile-service-overview>>
* <<transactions>>
* <<spans>>
* <<errors>>
@ -53,6 +54,8 @@ include::service-maps.asciidoc[]
include::service-overview.asciidoc[]
include::mobile-service.asciidoc[]
include::transactions.asciidoc[]
include::spans.asciidoc[]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 KiB

After

Width:  |  Height:  |  Size: 383 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 KiB

After

Width:  |  Height:  |  Size: 460 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 974 KiB

After

Width:  |  Height:  |  Size: 174 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 456 KiB

After

Width:  |  Height:  |  Size: 580 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 KiB

After

Width:  |  Height:  |  Size: 549 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 KiB

After

Width:  |  Height:  |  Size: 259 KiB

Before After
Before After

View file

@ -7,7 +7,7 @@
The APM app in {kib} allows you to monitor your software services and applications in real-time;
visualize detailed performance information on your services,
identify and analyze errors,
and monitor host-level and agent-specific metrics like JVM and Go runtime metrics.
and monitor host-level and APM agent-specific metrics like JVM and Go runtime metrics.
[float]
[[apm-bottlenecks]]

View file

@ -2,7 +2,7 @@
[[metrics]]
=== Metrics
The *Metrics* overview provides agent-specific metrics,
The *Metrics* overview provides APM agent-specific metrics,
which lets you perform more in-depth root cause analysis investigations within the APM app.
If you're experiencing a problem with your service, you can use this page to attempt to find the underlying cause.
@ -11,7 +11,7 @@ For example, you might be able to correlate a high number of errors with a long
[role="screenshot"]
image::apm/images/apm-metrics.png[Example view of the Metrics overview in APM app in Kibana]
If you're using the Java Agent, you can view metrics for each JVM.
If you're using the Java APM agent, you can view metrics for each JVM.
[role="screenshot"]
image::apm/images/jvm-metrics-overview.png[Example view of the Metrics overview for the Java Agent]

View file

@ -0,0 +1,59 @@
[role="xpack"]
[[mobile-service-overview]]
=== Mobile service overview
Selecting a mobile service brings you to the *Mobile service overview*.
The *Mobile service overview* contains a wide variety of charts and tables that provide
high-level visibility into how a mobile service is performing for your users--enabling you
to make data-driven decisions about how to improve your user experience.
For example, see:
* Crash Rate (Crashes per minute) -- coming soon
* Slowest App load time -- coming soon
* Number of sessions
* Number of HTTP requests
* Map showing the total number of HTTP requests based on country and region
* Most used devices, network connection type, OS version, and app version
* Latency, throughput, and errors over time
* Service dependencies
All of these metrics & insights can help SREs and developers better understand the health
of their mobile application environment and the impact of backend errors and bottlenecks on end-user experience.
[discrete]
[[mobile-service-stats]]
=== Quick stats
Understand the impact of slow application load times and variations in application crash rate on user traffic (coming soon).
Visualize session and HTTP trends, and see where your users are located--enabling you to optimize your infrastructure deployment and routing topology.
[role="screenshot"]
image::apm/images/mobile-location.png[mobile service overview centered on location map]
[discrete]
[[mobile-service-most-used]]
=== Most used
Optimize your end-user experience and your application QA strategy based on your most used device models and operating system versions.
[role="screenshot"]
image::apm/images/mobile-most-used.png[mobile service overview showing most used devices, network, OS, and app version]
[discrete]
[[mobile-throughput-transactions]]
=== Throughput and transactions
include::./service-overview.asciidoc[tag=throughput-transactions]
[discrete]
[[mobile-error-and-dependencies]]
=== Failed transaction rate and dependencies
include::./service-overview.asciidoc[tag=ftr]
include::./service-overview.asciidoc[tag=dependencies]
[role="screenshot"]
image::apm/images/mobile-tp.png[mobile service overview showing latency, throughput, and errors]

View file

@ -55,19 +55,20 @@ By default, all instrumented services and connections are shown.
Whether you're onboarding a new engineer, or just trying to grasp the big picture,
drag things around, zoom in and out, and begin to visualize how your services are connected.
Customize what the service map displays using either the query bar or the environment selector.
The query bar enables you to use <<advanced-queries,advanced queries>> to customize the service map based on your needs.
The environment selector allows you to narrow displayed results to a specific environment.
This can be useful if you have two or more services, in separate environments, but with the same name.
Use the environment drop-down to only see the data you're interested in, like `dev` or `production`.
If there's a specific service that interests you, select that service to highlight its connections.
Clicking **Focus map** will refocus the map on that specific service and lock the connection highlighting.
From here, select **Service Details**, or click on the **Transaction** tab to jump to the Transaction overview
for the selected service.
You can also use the tabs at the top of the page to easily jump to the **Errors** or **Metrics** overview.
Filter out your maps by picking the environment from the environment drop-down filter.
This can be useful if you have two or more services, in separate environments, but with the same name.
Use the environment drop-down to only see the data you're interested in, like `dev` or `production`.
Additional filters are not currently available for service maps.
[role="screenshot"]
image::apm/images/service-maps-java.png[Example view of service maps with Java highlighted in the APM app in Kibana]
image::apm/images/service-maps-java.png[Example view of service maps in the APM app in Kibana]
[float]
[[service-map-anomaly-detection]]
@ -95,16 +96,16 @@ To learn how to create a machine learning job, see <<machine-learning-integratio
Nodes appear on the map in one of two shapes:
* **Circle**: Instrumented services. Interior icons are based on the language of the agent used.
* **Circle**: Instrumented services. Interior icons are based on the language of the APM agent used.
* **Diamond**: Databases, external, and messaging. Interior icons represent the generic type,
with specific icons for known entities, like Elasticsearch.
Type and subtype are based on `span.type`, and `span.subtype`.
[float]
[[service-maps-supported]]
=== Supported APM Agents
=== Supported APM agents
Service maps are supported for the following Agent versions:
Service maps are supported for the following APM agent versions:
[horizontal]
Go agent:: ≥ v1.7.0

View file

@ -2,11 +2,11 @@
[[service-overview]]
=== Service overview
Selecting a <<services,*service*>> brings you to the *Service overview*.
Selecting a non-mobile <<services,*service*>> brings you to the *Service overview*.
The *Service overview* contains a wide variety of charts and tables that provide
high-level visibility into how a service is performing across your infrastructure:
* Service details like service version, runtime version, framework, and agent name and version
* Service details like service version, runtime version, framework, and APM agent name and version
* Container and orchestration information
* Cloud provider, machine type, service name, region, and availability zone
* Serverless function names and event trigger type
@ -61,6 +61,7 @@ image::apm/images/latency.png[Service latency]
[[service-throughput-transactions]]
=== Throughput and transactions
// tag::throughput-transactions[]
The *Throughput* chart visualizes the average number of transactions per minute for the selected service.
The *Transactions* table displays a list of _transaction groups_ for the
@ -73,11 +74,13 @@ list of similar transactions on the <<transactions, transactions overview>> page
[role="screenshot"]
image::apm/images/traffic-transactions.png[Traffic and transactions]
// end::throughput-transactions[]
[discrete]
[[service-error-rates]]
=== Failed transaction rate and errors
// tag::ftr[]
The failed transaction rate represents the percentage of failed transactions from the perspective of the selected service.
It's useful for visualizing unexpected increases, decreases, or irregular patterns in a service's transactions.
@ -91,6 +94,7 @@ These spans will set `event.outcome=failure` and increase the failed transaction
If there is no HTTP status, both transactions and spans are considered successful unless an error is reported.
====
// end::ftr[]
The *Errors* table provides a high-level view of each error message when it first and last occurred,
along with the total number of occurrences. This makes it very easy to quickly see which errors affect
@ -105,10 +109,11 @@ image::apm/images/error-rate.png[failed transaction rate and errors]
The *Time spent by span type* chart visualizes each span type's average duration and helps you determine
which spans could be slowing down transactions. The "app" label displayed under the
chart indicates that something was happening within the application. This could signal that the
chart indicates that something was happening within the application. This could signal that the APM
agent does not have auto-instrumentation for whatever was happening during that time or that the time was spent in the
application code and not in database or external requests.
// tag::dependencies[]
The *Dependencies* table displays a list of downstream services or external connections relevant
to the service at the selected time range. The table displays latency, throughput, failed transaction rate, and the impact of
each dependency. By default, dependencies are sorted by _Impact_ to show the most used and the slowest dependency.
@ -119,14 +124,20 @@ requires an agent version ≥ v5.6.3.
[role="screenshot"]
image::apm/images/spans-dependencies.png[Span type duration and dependencies]
// end::dependencies[]
[discrete]
[[service-cold-start]]
=== Cold start rate
The cold start rate chart is specific to serverless services.
It displays the percentage of requests that trigger a cold start of a serverless function.
See <<apm-lambda-cold-start-info>> for more information.
The cold start rate chart is specific to serverless services, and displays the
percentage of requests that trigger a cold start of a serverless function.
A cold start occurs when a serverless function has not been used for a certain period of time.
Analyzing the cold start rate can be useful for deciding how much memory to allocate to a function,
or when to remove a large dependency.
The cold start rate chart is currently supported for <<apm-lambda-cold-start-info,AWS Lambda>>
functions and Azure functions.
[role="screenshot"]
image::apm/images/lambda-cold-start.png[lambda cold start graph]
@ -157,7 +168,7 @@ image::apm/images/metadata-icons.png[Service metadata]
* Service version
* Runtime name and version
* Framework name
* Agent name and version
* APM agent name and version
*Container information*

View file

@ -8,11 +8,7 @@
APM is available via the navigation sidebar in {Kib}.
If you have not already installed and configured Elastic APM,
follow the three steps on the *Add data* page to get started:
. Start APM Server
. Add APM agents
. Load Kibana objects
follow the steps on the *Add data* page to get started.
[role="screenshot"]
image::apm/images/apm-setup.png[Installation instructions on the APM page in Kibana]

View file

@ -23,6 +23,22 @@ Each span has a type and is defined by a different color in the timeline/waterfa
[role="screenshot"]
image::apm/images/apm-span-detail.png[Example view of a span detail in the APM app in Kibana]
[float]
[[trace-sample-investigate]]
==== Investigate
The trace sample timeline features an **Investigate** button which provides a quick way to jump
to other areas of the Elastic Observability UI while maintaining the context of the currently selected trace sample.
For example, quickly view:
* logs and metrics for the selected pod
* logs and metrics for the selected host
* trace logs for the selected `trace.id`
* uptime status of the selected domain
* the <<service-maps,service map>> filtered by the selected trace
* the selected transaction in <<discover,Discover>>
* your <<custom-links,custom links>>
[float]
[[distributed-tracing]]
==== Distributed tracing

View file

@ -74,7 +74,7 @@ tune the APM agent or agents that are collecting the data.
You can disable the collection of specific metrics with the **disable metrics** configuration.
Or, you can set the **metrics interval** to zero seconds to deactivate metrics entirely.
Most APM agents support both options.
See the relevant {apm-agents-ref}[agent configuration options] for more details.
See the relevant {apm-agents-ref}[APM agent configuration options] for more details.
[float]
===== Reduce the number of errors

View file

@ -44,7 +44,7 @@ For example, is your app spending time in external calls, database processing, o
+
The time a transaction took to complete is also recorded and displayed on the chart under the "app" label.
"app" indicates that something was happening within the application, but we're not sure exactly what.
This could be a sign that the agent does not have auto-instrumentation for whatever was happening during that time.
This could be a sign that the APM agent does not have auto-instrumentation for whatever was happening during that time.
+
It's important to note that if you have asynchronous spans, the sum of all span times may exceed the duration of the transaction.
@ -71,7 +71,7 @@ If there's a particular endpoint you're worried about, you can click on it to vi
[IMPORTANT]
====
If you only see one route in the Transactions table, or if you have transactions named "unknown route",
it could be a symptom that the agent either wasn't installed correctly or doesn't support your framework.
it could be a symptom that the APM agent either wasn't installed correctly or doesn't support your framework.
For further details, including troubleshooting and custom implementation instructions,
refer to the documentation for each {apm-agents-ref}[APM Agent] you've implemented.
@ -81,7 +81,7 @@ refer to the documentation for each {apm-agents-ref}[APM Agent] you've implement
[[rum-transaction-overview]]
=== RUM Transaction overview
The transaction overview page is customized for the JavaScript RUM Agent.
The transaction overview page is customized for the JavaScript RUM agent.
Specifically, the page highlights *page load times* for your service:
[role="screenshot"]
@ -144,13 +144,13 @@ NOTE: More information on timeline waterfalls is available in <<spans, spans>>.
Learn more about a trace sample in the *Metadata* tab:
* Labels - Custom labels added by agents
* Labels - Custom labels added by APM agents
* HTTP request/response information
* Host information
* Container information
* Service - The service/application runtime, agent, name, etc..
* Service - The service/application runtime, APM agent, name, etc..
* Process - The process id that served up the request.
* Agent information
* APM agent information
* URL
* User - Requires additional configuration, but allows you to see which user experienced the current transaction.
* FaaS information, like cold start, AWS request ID, trigger type, and trigger request ID

View file

@ -58,20 +58,20 @@ To force a rollover, use the {ref}/indices-rollover-index.html[rollover API] to
[[troubleshooting-too-many-transactions]]
=== Too many unique transaction names
Transaction names are defined in each APM Agent; when an Agent supports a framework,
Transaction names are defined in each APM agent; when an APM agent supports a framework,
it includes logic for naming the transactions that the framework creates.
In some cases though, like when using an Agent's API to create custom transactions,
In some cases though, like when using an APM agent's API to create custom transactions,
it is up to the user to define a pattern for transaction naming.
When transactions are named incorrectly, each unique URL can be associated with a unique transaction group—causing
an explosion in the number of transaction groups per service, and leading to inaccuracies in the APM app.
To fix a large number of unique transaction names,
you need to change how you are using the Agent API to name your transactions.
you need to change how you are using the APM agent API to name your transactions.
To do this, ensure you are **not** naming based on parameters that can change.
For example, user ids, product ids, order numbers, query parameters, etc.,
should be stripped away, and commonality should be found between your unique URLs.
Let's look at an example from the RUM Agent documentation. Here are a few URLs you might find on Elastic.co:
Let's look at an example from the RUM agent documentation. Here are a few URLs you might find on Elastic.co:
[source,yml]
----
@ -109,14 +109,14 @@ You will see this warning if your results have more than `1000` unique transacti
**More information**
While this can happen with any APM Agent, it typically occurs with the RUM Agent.
For more information on how to correctly set `transaction.name` in the RUM Agent,
While this can happen with any APM agent, it typically occurs with the RUM agent.
For more information on how to correctly set `transaction.name` in the RUM agent,
see {apm-rum-ref}/custom-transaction-name.html[custom initial page load transaction names].
The RUM Agent can also set the `transaction.name` when observing for transaction events.
The RUM agent can also set the `transaction.name` when observing for transaction events.
See {apm-rum-ref}/agent-api.html#observe[`apm.observe()`] for more information.
If your problem is occurring in a different Agent, the tips above still apply.
If your problem is occurring in a different APM agent, the tips above still apply.
See the relevant {apm-agents-ref}[Agent API documentation] to adjust how you're naming your transactions.
[float]
@ -128,17 +128,17 @@ when the transactions in your services are named correctly.
If you're seeing "GET unknown route" or "unknown route" in the APM app,
it could be a sign that something isn't working as it should.
Elastic APM Agents come with built-in support for popular frameworks out-of-the-box.
This means, among other things, that the Agent will try to automatically name HTTP requests.
As an example, the Node.js Agent uses the route that handled the request, while the Java Agent uses the Servlet name.
Elastic APM agents come with built-in support for popular frameworks out-of-the-box.
This means, among other things, that the APM agent will try to automatically name HTTP requests.
As an example, the Node.js agent uses the route that handled the request, while the Java agent uses the Servlet name.
"Unknown route" indicates that the Agent can't determine what to name the request,
perhaps because the technology you're using isn't supported, the Agent has been installed incorrectly,
or because something is happening to the request that the Agent doesn't understand.
"Unknown route" indicates that the APM agent can't determine what to name the request,
perhaps because the technology you're using isn't supported, the agent has been installed incorrectly,
or because something is happening to the request that the agent doesn't understand.
To resolve this, you'll need to head over to the relevant {apm-agents-ref}[Agent documentation].
Specifically, view the Agent's supported technologies page.
You can also use the Agent's public API to manually set a name for the transaction.
To resolve this, you'll need to head over to the relevant {apm-agents-ref}[APM agent documentation].
Specifically, view the agent's supported technologies page.
You can also use the agent's public API to manually set a name for the transaction.
[float]
[[troubleshooting-fields-unsearchable]]
@ -148,7 +148,7 @@ In Elasticsearch, index templates are used to define settings and mappings that
The recommended index templates for APM are installed by {fleet} when the Elastic APM integration is installed.
These templates, by default, enable and disable indexing on certain fields.
As an example, some agents store cookie values in `http.request.cookies`.
As an example, some APM agents store cookie values in `http.request.cookies`.
Since `http.request` has disabled dynamic indexing, and `http.request.cookies` is not declared in a custom mapping,
the values in `http.request.cookies` are not indexed and thus not searchable.
@ -187,5 +187,5 @@ This setting is necessary, for example, for cross-origin requests.
If you have a basic web application that provides data via an API on `localhost:4000`,
and serves HTML from `localhost:4001`, you'd need to set `distributedTracingOrigins: ['https://localhost:4000']`
to ensure the origin is monitored as a part of distributed tracing.
In other words, `distributedTracingOrigins` is consulted prior to the agent adding the
In other words, `distributedTracingOrigins` is consulted prior to the APM agent adding the
distributed tracing `traceparent` header to each request.

View file

@ -81,7 +81,7 @@ export TEST_BROWSER_HEADLESS=1
export TEST_THROTTLE_NETWORK=1
----------
** When running against a Cloud deployment, some tests are not applicable. To skip tests that do not apply, use --exclude-tag. An example shell file can be found at: {blob}test/scripts/jenkins_cloud.sh[test/scripts/jenkins_cloud.sh]
** When running against a Cloud deployment, some tests are not applicable. To skip tests that do not apply, use --exclude-tag. An example shell file can be found at: {kibana-blob}test/scripts/jenkins_cloud.sh[test/scripts/jenkins_cloud.sh]
+
["source", "shell"]
----------
@ -118,7 +118,7 @@ The tests are written in https://mochajs.org[mocha] using https://github.com/ela
We use https://www.w3.org/TR/webdriver1/[WebDriver Protocol] to run tests in both Chrome and Firefox with the help of https://sites.google.com/a/chromium.org/chromedriver/[chromedriver] and https://firefox-source-docs.mozilla.org/testing/geckodriver/[geckodriver]. When the `FunctionalTestRunner` launches, remote service creates a new webdriver session, which starts the driver and a stripped-down browser instance. We use `browser` service and `webElementWrapper` class to wrap up https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/[Webdriver API].
The `FunctionalTestRunner` automatically transpiles functional tests using babel, so that tests can use the same ECMAScript features that {kib} source code uses. See {blob}style_guides/js_style_guide.md[style_guides/js_style_guide.md].
The `FunctionalTestRunner` automatically transpiles functional tests using babel, so that tests can use the same ECMAScript features that {kib} source code uses. See {kibana-blob}style_guides/js_style_guide.md[style_guides/js_style_guide.md].
[discrete]
==== Definitions
@ -270,7 +270,7 @@ The first and only argument to all providers is a Provider API Object. This obje
Within config files the API has the following properties
[horizontal]
`log`::: An instance of the {blob}packages/kbn-dev-utils/src/tooling_log/tooling_log.js[`ToolingLog`] that is ready for use
`log`::: An instance of the {kibana-blob}packages/kbn-dev-utils/src/tooling_log/tooling_log.js[`ToolingLog`] that is ready for use
`readConfigFile(path)`::: Returns a promise that will resolve to a Config instance that provides the values from the config file at `path`
Within service and PageObject Providers the API is:
@ -293,17 +293,17 @@ Within a test Provider the API is exactly the same as the service providers API
The `FunctionalTestRunner` comes with three built-in services:
**config:**:::
* Source: {blob}src/functional_test_runner/lib/config/config.ts[src/functional_test_runner/lib/config/config.ts]
* Schema: {blob}src/functional_test_runner/lib/config/schema.ts[src/functional_test_runner/lib/config/schema.ts]
* Source: {kibana-blob}src/functional_test_runner/lib/config/config.ts[src/functional_test_runner/lib/config/config.ts]
* Schema: {kibana-blob}src/functional_test_runner/lib/config/schema.ts[src/functional_test_runner/lib/config/schema.ts]
* Use `config.get(path)` to read any value from the config file
**log:**:::
* Source: {blob}packages/kbn-dev-utils/src/tooling_log/tooling_log.js[packages/kbn-dev-utils/src/tooling_log/tooling_log.js]
* Source: {kibana-blob}packages/kbn-dev-utils/src/tooling_log/tooling_log.js[packages/kbn-dev-utils/src/tooling_log/tooling_log.js]
* `ToolingLog` instances are readable streams. The instance provided by this service is automatically piped to stdout by the `FunctionalTestRunner` CLI
* `log.verbose()`, `log.debug()`, `log.info()`, `log.warning()` all work just like console.log but produce more organized output
**lifecycle:**:::
* Source: {blob}src/functional_test_runner/lib/lifecycle.ts[src/functional_test_runner/lib/lifecycle.ts]
* Source: {kibana-blob}src/functional_test_runner/lib/lifecycle.ts[src/functional_test_runner/lib/lifecycle.ts]
* Designed primary for use in services
* Exposes lifecycle events for basic coordination. Handlers can return a promise and resolve/fail asynchronously
* Phases include: `beforeLoadTests`, `beforeTests`, `beforeEachTest`, `cleanup`
@ -314,14 +314,14 @@ The `FunctionalTestRunner` comes with three built-in services:
The {kib} functional tests define the vast majority of the actual functionality used by tests.
**browser**:::
* Source: {blob}test/functional/services/browser.ts[test/functional/services/browser.ts]
* Source: {kibana-blob}test/functional/services/browser.ts[test/functional/services/browser.ts]
* Higher level wrapper for `remote` service, which exposes available browser actions
* Popular methods:
** `browser.getWindowSize()`
** `browser.refresh()`
**testSubjects:**:::
* Source: {blob}test/functional/services/test_subjects.ts[test/functional/services/test_subjects.ts]
* Source: {kibana-blob}test/functional/services/test_subjects.ts[test/functional/services/test_subjects.ts]
* Test subjects are elements that are tagged specifically for selecting from tests
* Use `testSubjects` over CSS selectors when possible
* Usage:
@ -346,21 +346,21 @@ await testSubjects.click(containerButton);
** `testSubjects.click(testSubjectSelector)` - Click a test subject in the page; throw if it can't be found after some time
**find:**:::
* Source: {blob}test/functional/services/find.ts[test/functional/services/find.ts]
* Source: {kibana-blob}test/functional/services/find.ts[test/functional/services/find.ts]
* Helpers for `remote.findBy*` methods that log and manage timeouts
* Popular methods:
** `find.byCssSelector()`
** `find.allByCssSelector()`
**retry:**:::
* Source: {blob}test/common/services/retry/retry.ts[test/common/services/retry/retry.ts]
* Source: {kibana-blob}test/common/services/retry/retry.ts[test/common/services/retry/retry.ts]
* Helpers for retrying operations
* Popular methods:
** `retry.try(fn, onFailureBlock)` - Execute `fn` in a loop until it succeeds or the default timeout elapses. The optional `onFailureBlock` is executed before each retry attempt.
** `retry.tryForTime(ms, fn, onFailureBlock)` - Execute `fn` in a loop until it succeeds or `ms` milliseconds elapses. The optional `onFailureBlock` is executed before each retry attempt.
**kibanaServer:**:::
* Source: {blob}test/common/services/kibana_server/kibana_server.js[test/common/services/kibana_server/kibana_server.js]
* Source: {kibana-blob}test/common/services/kibana_server/kibana_server.js[test/common/services/kibana_server/kibana_server.js]
* Helpers for interacting with {kib}'s server
* Commonly used methods:
** `kibanaServer.uiSettings.update()`
@ -368,23 +368,23 @@ await testSubjects.click(containerButton);
** `kibanaServer.status.getOverallState()`
**esArchiver:**:::
* Source: {blob}test/common/services/es_archiver.ts[test/common/services/es_archiver.ts]
* Source: {kibana-blob}test/common/services/es_archiver.ts[test/common/services/es_archiver.ts]
* Load/unload archives created with the `esArchiver`
* Popular methods:
** `esArchiver.load(path)`
** `esArchiver.loadIfNeeded(path)`
** `esArchiver.unload(path)`
Full list of services that are used in functional tests can be found here: {blob}test/functional/services[test/functional/services]
Full list of services that are used in functional tests can be found here: {kibana-blob}test/functional/services[test/functional/services]
**Low-level utilities:**:::
* es
** Source: {blob}test/common/services/es.ts[test/common/services/es.ts]
** Source: {kibana-blob}test/common/services/es.ts[test/common/services/es.ts]
** {es} client
** Higher level options: `kibanaServer.uiSettings` or `esArchiver`
* remote
** Source: {blob}test/functional/services/remote/remote.ts[test/functional/services/remote/remote.ts]
** Source: {kibana-blob}test/functional/services/remote/remote.ts[test/functional/services/remote/remote.ts]
** Instance of https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html[WebDriver] class
** Responsible for all communication with the browser
** To perform browser actions, use `remote` service

View file

@ -1,44 +1,34 @@
[[interpreting-ci-failures]]
== Interpreting CI Failures
{kib} CI uses a Jenkins feature called "Pipelines" to automate testing of the code in pull requests and on tracked branches. Pipelines are defined within the repository via the `Jenkinsfile` at the root of the project.
{kib} CI uses a Buildkite feature called "Pipelines" to automate testing of the code in pull requests and on tracked branches. Pipelines are defined within the repository via the `Pipelines` at the `.buildkite/pipelines` folder.
More information about Jenkins Pipelines can be found link:https://jenkins.io/doc/book/pipeline/[in the Jenkins book].
More information about Buildkite Pipelines can be found link:https://buildkite.com/docs/pipelines[in the docs].
[discrete]
=== Github Checks
When a test fails it will be reported to Github via Github Checks. We currently bucket tests into several categories which run in parallel to make CI faster. Groups like `ciGroup{X}` get a single check in Github, and other tests like linting, or type checks, get their own checks.
Clicking the link next to the check in the conversation tab of a pull request will take you to the log output from that section of the tests. If that log output is truncated, or doesn't clearly identify what happened, you can usually get more complete information by visiting Jenkins directly.
Clicking the link next to the check in the conversation tab of a pull request will take you to the log output from that section of the tests. If that log output is truncated, or doesn't clearly identify what happened, you can usually get more complete information by visiting Buildkite directly.
[discrete]
=== Viewing Job Executions in Jenkins
=== Viewing Job Executions in Kibana
To view the results of a job execution in Jenkins, either click the link in the comment left by `@elasticmachine` or search for the `kibana-ci` check in the list at the bottom of the PR. This link will take you to the top-level page for the specific job execution that failed.
To view the results of a job execution in Buildkite, either click the link in the comment left by `@elasticmachine` or search for the `kibana-ci` check in the list at the bottom of the PR. This link will take you to the top-level page for the specific job execution that failed.
image::images/job_view.png[Jenkins job view showing a test failure]
image::images/job_view.png[Buildkite pipeline view showing a few test failures]
1. *Git Changes:* the list of commits that were in this build which weren't in the previous build. For Pull Requests this list is calculated by comparing against the most recent Pull Request which was tested, it is not limited to build for this specific Pull Request, so it's not very useful.
2. *Test Results:* A link to the test results screen, and shortcuts to the failed tests. Functional tests capture and store the log output from each specific test, and make it visible at these links. For other test runners only the error message is visible and log output must be tracked down in the *Pipeline Steps*.
3. *Google Cloud Storage (GCS) Upload Report:* Link to the screen which lists out the artifacts uploaded to GCS during this job execution.
4. *Pipeline Steps:*: A breakdown of the pipeline that was executed, along with individual log output for each step in the pipeline.
[discrete]
=== Viewing ciGroup/test Logs
To view the logs for a failed specific ciGroup, jest, type checkers, linters, etc., click on the *Pipeline Steps* link in from the Job page.
image::images/pipeline_steps_view.png[Jenkins pipeline steps screenshot]
Scroll down the page until you find a failed step *(1)*, and then look up a few lines for the `Branch:` step to see which specific job this is. If this is the job you're looking for click the little terminal icon next to the failed step *(1)* to view the logs for that specific step in the Pipeline.
1. *Git commit:* the git commit that caused this build.
2. *Test Results:* A link to the test results screen, and shortcuts to the logs and jobs of the failed tests. Functional tests capture and store the log output from each specific test, and make it visible at these links.
3. *Pipeline Steps:*: A breakdown of the pipeline that was executed, along with individual log output for each step in the pipeline.
[discrete]
=== Debugging Functional UI Test Failures
The logs in Pipeline Steps contain `Info` level logging. To debug Functional UI tests it's usually helpful to see the debug logging. You can go to the list of all tests including failures (1), or directly to the failures (2).
The logs in Pipeline Steps contain `Info` level logging. To debug Functional UI tests it's usually helpful to see the debug logging. You can go to the test failure details by clicking on the *logs* (1).
image::images/test_results.png[Jenkisn build screenshot]
image::images/test_results.png[Buildkite build screenshot]
Looking at the failure, we first look at the Error and stack trace. In the example below, this test failed to find an element within the timeout;
`Error: retry.try timeout: TimeoutError: Waiting for element to be located By(css selector, [data-test-subj="createSpace"])`

Binary file not shown.

Before

Width:  |  Height:  |  Size: 624 KiB

After

Width:  |  Height:  |  Size: 570 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 443 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 KiB

After

Width:  |  Height:  |  Size: 324 KiB

Before After
Before After

View file

@ -431,7 +431,7 @@ The plugin exposes the static DefaultEditorController class to consume.
|{kib-repo}blob/{branch}/x-pack/plugins/apm/readme.md[apm]
|undefined
|This plugin provides access to App Monitoring features provided by Elastic. It allows you to monitor your software services and applications in real-time; visualize detailed performance information on your services, identify and analyze errors, and monitor host-level and APM agent-specific metrics like JVM and Go runtime metrics.
|{kib-repo}blob/{branch}/x-pack/plugins/banners/README.md[banners]

View file

@ -64,7 +64,7 @@ export default async function ({ readConfigFile }) {
}
// more settings, like timeouts, mochaOpts, etc are
// defined in the config schema. See {blob}src/functional_test_runner/lib/config/schema.js[src/functional_test_runner/lib/config/schema.js]
// defined in the config schema. See {kibana-blob}src/functional_test_runner/lib/config/schema.js[src/functional_test_runner/lib/config/schema.js]
};
}

View file

@ -47,9 +47,9 @@ To use {kib} i18n tooling, create a `.i18nrc.json` file with the following confi
}
-----------
An example {kib} `.i18nrc.json` is {blob}.i18nrc.json[here].
An example {kib} `.i18nrc.json` is {kibana-blob}.i18nrc.json[here].
Full documentation about i18n tooling is {blob}src/dev/i18n/README.md[here].
Full documentation about i18n tooling is {kibana-blob}src/dev/i18n/README.md[here].
[discrete]
=== Extracting default messages

View file

@ -9,10 +9,6 @@ release-state can be: released | prerelease | unreleased
:major-version: 5.4
:branch: 5.4
:docker-image: docker.elastic.co/kibana/kibana:{version}
:es-ref: https://www.elastic.co/guide/en/elasticsearch/reference/{branch}/
:security: https://www.elastic.co/community/security/
include::{docs-root}/shared/attributes.asciidoc[]
include::introduction.asciidoc[]

View file

@ -1,26 +1,12 @@
[[kibana-guide]]
= Kibana Guide
:include-xpack: true
:lang: en
:kib-repo-dir: {kibana-root}/docs
include::{docs-root}/shared/versions/stack/{source_branch}.asciidoc[]
:docker-repo: docker.elastic.co/kibana/kibana
:docker-image: {docker-repo}:{version}
:es-docker-repo: docker.elastic.co/elasticsearch/elasticsearch
:es-docker-image: {es-docker-repo}:{version}
:security-ref: https://www.elastic.co/community/security/
:Data-source: Data view
:data-source: data view
:data-sources: data views
:a-data-source: a data view
include::{docs-root}/shared/attributes.asciidoc[]
:blob: {kib-repo}blob/{branch}/
include::user/index.asciidoc[]
include::accessibility.asciidoc[]

View file

@ -1,7 +1,9 @@
[role="xpack"]
[[maps-connect-to-ems]]
== Connect to Elastic Maps Service
:ems-docker-repo: docker.elastic.co/elastic-maps-service/elastic-maps-server-ubi8
:ems-docker-image: {ems-docker-repo}:{version}
https://www.elastic.co/elastic-maps-service[Elastic Maps Service (EMS)] is a service that hosts
tile layers and vector shapes of administrative boundaries.
If you are using Kibana's out-of-the-box settings, Maps is already configured to use EMS.

View file

@ -1,7 +1,3 @@
:ems-docker-repo: docker.elastic.co/elastic-maps-service/elastic-maps-server-ubi8
:ems-docker-image: {ems-docker-repo}:{version}
[role="xpack"]
[[maps]]
= Maps

View file

@ -41,13 +41,6 @@ Refer to {ref}/security-basic-setup-https.html#encrypt-kibana-elasticsearch[Encr
See <<monitoring-kibana>>.
[role="exclude",id="settings-xpack-kb"]
== {xpack} Settings in {kib}
include::{asciidoc-dir}/../../shared/settings.asciidoc[]
For more {kib} configuration settings, see <<settings>>.
[role="exclude",id="uptime-security"]
== Uptime security

View file

@ -142,6 +142,8 @@ If configured in your `kibana.yml`, output settings are grayed out and
unavailable in the {fleet} UI. To make these settings editable in the UI, do not
configure them in the configuration file.
+
NOTE: The `xpack.fleet.outputs` settings are intended for advanced configurations such as having multiple outputs. We recommend not enabling the `xpack.fleet.agents.elasticsearch.host` settings when using `xpack.fleet.outputs`.
+
.Required properties of `xpack.fleet.outputs`
[%collapsible%open]
=====
@ -161,7 +163,9 @@ configure them in the configuration file.
[%collapsible%open]
=====
`is_default`:::
If `true`, this output is the default output.
If `true`, the output specified in `xpack.fleet.outputs` will be the one used to send agent data unless there is another one configured specifically for the agent policy.
`is_default_monitoring`:::
If `true`, the output specified in `xpack.fleet.outputs` will be the one used to send agent monitoring data unless there is another one configured specifically for the agent policy.
=====
+
Example configuration:

View file

@ -1,22 +0,0 @@
[role="xpack"]
[[settings-xpack-kb]]
== {xpack} settings in {kib}
[subs="attributes"]
++++
<titleabbrev>{xpack} settings</titleabbrev>
++++
include::{asciidoc-dir}/../../shared/settings.asciidoc[]
For more {kib} configuration settings, see <<settings>>.
include::alert-action-settings.asciidoc[]
include::apm-settings.asciidoc[]
include::banners-settings.asciidoc[]
include::infrastructure-ui-settings.asciidoc[]
include::logs-ui-settings.asciidoc[]
include::reporting-settings.asciidoc[]
include::spaces-settings.asciidoc[]
include::task-manager-settings.asciidoc[]
include::i18n-settings.asciidoc[]
include::fleet-settings.asciidoc[]

View file

@ -4,6 +4,11 @@
<titleabbrev>Install with Docker</titleabbrev>
++++
:docker-repo: docker.elastic.co/kibana/kibana
:docker-image: {docker-repo}:{version}
:es-docker-repo: docker.elastic.co/elasticsearch/elasticsearch
:es-docker-image: {es-docker-repo}:{version}
Docker images for {kib} are available from the Elastic Docker registry. The
base image is https://hub.docker.com/_/ubuntu[ubuntu:20.04].

View file

@ -166,7 +166,8 @@ responses:
Click the rule name to access a rule details page:
[role="screenshot"]
image::images/rule-details-alerts-active.png[Rule details page with three alerts]
image::images/rule-details-alerts-active.png[Rule details page with multiple alerts]
// NOTE: This is an autogenerated screenshot. Do not edit it directly.
In this example, the rule detects when a site serves more than a threshold number of bytes in a 24 hour period. Four sites are above the threshold. These are called alerts - occurrences of the condition being detected - and the alert name, status, time of detection, and duration of the condition are shown in this view. Alerts come and go from the list depending on whether the rule conditions are met.
@ -182,4 +183,4 @@ You can suppress future actions for a specific alert by turning on the *Mute* to
[role="screenshot"]
image::images/rule-details-disabling.png[Use the disable toggle to turn off rule checks and clear alerts tracked]
// NOTE: This is an autogenerated screenshot. Do not edit it directly.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

After

Width:  |  Height:  |  Size: 193 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 852 KiB

After

Width:  |  Height:  |  Size: 273 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 170 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

After

Width:  |  Height:  |  Size: 234 KiB

Before After
Before After

View file

@ -14,7 +14,7 @@ For example:
[source,sh]
--------------------------------------------------
`GET kbn:/api/index_management/indices`
GET kbn:/api/index_management/indices
--------------------------------------------------
Note: this will automatically prefix `s/{space_id}/` on the API request if ran from a non-default Kibana Space.

View file

@ -1,8 +1,6 @@
[[whats-new]]
== What's new in {minor-version}
coming::[8.7.0]
Here are the highlights of what's new and improved in {minor-version}.
For detailed information about this release,
check the <<release-notes, release notes>>.

View file

@ -24,7 +24,7 @@
[
{
"name": "apm",
"version": "8.7.0-preview-1678362302",
"version": "8.7.1-preview-1680253486",
"forceAlignStackVersion": true,
"allowSyncToPrerelease": true
},
@ -46,6 +46,6 @@
},
{
"name": "security_detection_engine",
"version": "8.7.1"
"version": "8.7.2"
}
]

View file

@ -11,7 +11,7 @@
"dashboarding"
],
"private": true,
"version": "8.7.0",
"version": "8.7.1",
"branch": "8.7",
"types": "./kibana.d.ts",
"tsdocMetadata": "./build/tsdoc-metadata.json",
@ -1026,7 +1026,7 @@
"backport": "^8.9.7",
"callsites": "^3.1.0",
"chance": "1.0.18",
"chromedriver": "^110.0.0",
"chromedriver": "^112.0.0",
"clean-webpack-plugin": "^3.0.0",
"compression-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^6.0.2",

View file

@ -36,7 +36,7 @@ export interface FullStorySnippetConfig {
}
export function loadSnippet({
scriptUrl = 'edge.fullstory.com/s/fs.js',
scriptUrl = 'https://edge.fullstory.com/s/fs.js',
fullStoryOrgId,
host = 'fullstory.com',
namespace = 'FS',

View file

@ -366,12 +366,13 @@ export const getEuiContextMapping = (): EuiTokensObject => {
values={{ searchValue }}
/>
),
'euiComboBoxOptionsList.delimiterMessage': ({ delimiter }: EuiValues) =>
i18n.translate('core.euiComboBoxOptionsList.delimiterMessage', {
defaultMessage: 'Add each item separated by {delimiter}',
values: { delimiter },
description: 'Screen reader text describing adding delimited options',
}),
'euiComboBoxOptionsList.delimiterMessage': ({ delimiter }: EuiValues) => (
<FormattedMessage
id="core.euiComboBoxOptionsList.delimiterMessage"
defaultMessage="Add each item separated by {delimiter}"
values={{ delimiter }}
/>
),
'euiComboBoxPill.removeSelection': ({ children }: EuiValues) =>
i18n.translate('core.euiComboBoxPill.removeSelection', {
defaultMessage: 'Remove {children} from selection in this group',

View file

@ -1,145 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { ensureDeepObject } from './ensure_deep_object';
test('flat object', () => {
const obj = {
'foo.a': 1,
'foo.b': 2,
};
expect(ensureDeepObject(obj)).toEqual({
foo: {
a: 1,
b: 2,
},
});
});
test('deep object', () => {
const obj = {
foo: {
a: 1,
b: 2,
},
};
expect(ensureDeepObject(obj)).toEqual({
foo: {
a: 1,
b: 2,
},
});
});
test('flat within deep object', () => {
const obj = {
foo: {
b: 2,
'bar.a': 1,
},
};
expect(ensureDeepObject(obj)).toEqual({
foo: {
b: 2,
bar: {
a: 1,
},
},
});
});
test('flat then flat object', () => {
const obj = {
'foo.bar': {
b: 2,
'quux.a': 1,
},
};
expect(ensureDeepObject(obj)).toEqual({
foo: {
bar: {
b: 2,
quux: {
a: 1,
},
},
},
});
});
test('full with empty array', () => {
const obj = {
a: 1,
b: [],
};
expect(ensureDeepObject(obj)).toEqual({
a: 1,
b: [],
});
});
test('full with array of primitive values', () => {
const obj = {
a: 1,
b: [1, 2, 3],
};
expect(ensureDeepObject(obj)).toEqual({
a: 1,
b: [1, 2, 3],
});
});
test('full with array of full objects', () => {
const obj = {
a: 1,
b: [{ c: 2 }, { d: 3 }],
};
expect(ensureDeepObject(obj)).toEqual({
a: 1,
b: [{ c: 2 }, { d: 3 }],
});
});
test('full with array of flat objects', () => {
const obj = {
a: 1,
b: [{ 'c.d': 2 }, { 'e.f': 3 }],
};
expect(ensureDeepObject(obj)).toEqual({
a: 1,
b: [{ c: { d: 2 } }, { e: { f: 3 } }],
});
});
test('flat with flat and array of flat objects', () => {
const obj = {
a: 1,
'b.c': 2,
d: [3, { 'e.f': 4 }, { 'g.h': 5 }],
};
expect(ensureDeepObject(obj)).toEqual({
a: 1,
b: { c: 2 },
d: [3, { e: { f: 4 } }, { g: { h: 5 } }],
});
});
test('array composed of flat objects', () => {
const arr = [{ 'c.d': 2 }, { 'e.f': 3 }];
expect(ensureDeepObject(arr)).toEqual([{ c: { d: 2 } }, { e: { f: 3 } }]);
});

View file

@ -1,50 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
const separator = '.';
/**
* Recursively traverses through the object's properties and expands ones with
* dot-separated names into nested objects (eg. { a.b: 'c'} -> { a: { b: 'c' }).
* @param obj Object to traverse through.
* @returns Same object instance with expanded properties.
*/
export function ensureDeepObject(obj: any): any {
if (obj == null || typeof obj !== 'object') {
return obj;
}
if (Array.isArray(obj)) {
return obj.map((item) => ensureDeepObject(item));
}
return Object.keys(obj).reduce((fullObject, propertyKey) => {
const propertyValue = obj[propertyKey];
if (!propertyKey.includes(separator)) {
fullObject[propertyKey] = ensureDeepObject(propertyValue);
} else {
walk(fullObject, propertyKey.split(separator), propertyValue);
}
return fullObject;
}, {} as any);
}
function walk(obj: any, keys: string[], value: any) {
const key = keys.shift()!;
if (keys.length === 0) {
obj[key] = value;
return;
}
if (obj[key] === undefined) {
obj[key] = {};
}
walk(obj[key], keys, ensureDeepObject(value));
}

View file

@ -10,8 +10,8 @@ import { readFileSync } from 'fs';
import { safeLoad } from 'js-yaml';
import { set } from '@kbn/safer-lodash-set';
import { ensureDeepObject } from '@kbn/std';
import { isPlainObject } from 'lodash';
import { ensureDeepObject } from './ensure_deep_object';
const readYaml = (path: string) => {
try {

View file

@ -14,6 +14,7 @@
"@kbn/safer-lodash-set",
"@kbn/utils",
"@kbn/config-schema",
"@kbn/std",
],
"exclude": [
"target/**/*",

View file

@ -140,6 +140,8 @@ export type ApmFields = Fields<{
values: number[];
counts: number[];
};
'transaction.result': string;
'transaction.sampled': boolean;
'service.environment': string;
'service.framework.name': string;
'service.framework.version': string;
@ -163,8 +165,6 @@ export type ApmFields = Fields<{
'span.self_time.sum.us': number;
'span.subtype': string;
'span.type': string;
'transaction.result': string;
'transaction.sampled': true;
'span.links': Array<{
trace: { id: string };
span: { id: string };

View file

@ -32,6 +32,7 @@ export class Transaction extends BaseSpan {
error.fields['trace.id'] = this.fields['trace.id'];
error.fields['transaction.id'] = this.fields['transaction.id'];
error.fields['transaction.type'] = this.fields['transaction.type'];
error.fields['transaction.sampled'] = this.fields['transaction.sampled'];
});
return this;
@ -43,6 +44,7 @@ export class Transaction extends BaseSpan {
error.fields['transaction.id'] = this.fields['transaction.id'];
error.fields['transaction.name'] = this.fields['transaction.name'];
error.fields['transaction.type'] = this.fields['transaction.type'];
error.fields['transaction.sampled'] = this.fields['transaction.sampled'];
});
this._errors.push(...errors);
@ -56,7 +58,10 @@ export class Transaction extends BaseSpan {
}
sample(sampled: boolean = true) {
this._sampled = sampled;
this._sampled = this.fields['transaction.sampled'] = sampled;
this._errors.forEach((error) => {
error.fields['transaction.sampled'] = sampled;
});
return this;
}

View file

@ -0,0 +1,5 @@
test: {
"aaa['__proto__.hello']": "Hello",
"aaa['__proto__.nested.there']": "There",
"aaa['__proto__.nested.here']": "This JS syntax is apparently valid for our parser"
}

View file

@ -0,0 +1,3 @@
test:
hello:
'__proto__.dolly': "Well hello there"

View file

@ -1,50 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
const separator = '.';
/**
* Recursively traverses through the object's properties and expands ones with
* dot-separated names into nested objects (eg. { a.b: 'c'} -> { a: { b: 'c' }).
* @param obj Object to traverse through.
* @returns Same object instance with expanded properties.
*/
export function ensureDeepObject(obj: any): any {
if (obj == null || typeof obj !== 'object') {
return obj;
}
if (Array.isArray(obj)) {
return obj.map((item) => ensureDeepObject(item));
}
return Object.keys(obj).reduce((fullObject, propertyKey) => {
const propertyValue = obj[propertyKey];
if (!propertyKey.includes(separator)) {
fullObject[propertyKey] = ensureDeepObject(propertyValue);
} else {
walk(fullObject, propertyKey.split(separator), propertyValue);
}
return fullObject;
}, {} as any);
}
function walk(obj: any, keys: string[], value: any) {
const key = keys.shift()!;
if (keys.length === 0) {
obj[key] = value;
return;
}
if (obj[key] === undefined) {
obj[key] = {};
}
walk(obj[key], keys, ensureDeepObject(value));
}

View file

@ -47,6 +47,18 @@ test('should throw an exception when referenced environment variable in a config
).toThrowErrorMatchingSnapshot();
});
test('throws parsing a config with forbidden paths', () => {
expect(() =>
getConfigFromFiles([fixtureFile('forbidden_1.yml')])
).toThrowErrorMatchingInlineSnapshot(`"Forbidden path detected: test.aaa.__proto__.hello"`);
});
test('throws parsing another config with forbidden paths', () => {
expect(() =>
getConfigFromFiles([fixtureFile('forbidden_2.yml')])
).toThrowErrorMatchingInlineSnapshot(`"Forbidden path detected: test.hello.__proto__"`);
});
describe('different cwd()', () => {
const originalCwd = process.cwd();
const tempCwd = resolve(__dirname);

View file

@ -11,7 +11,7 @@ import { safeLoad } from 'js-yaml';
import { set } from '@kbn/safer-lodash-set';
import { isPlainObject } from 'lodash';
import { ensureDeepObject } from './ensure_deep_object';
import { ensureDeepObject } from '@kbn/std';
const readYaml = (path: string) => safeLoad(readFileSync(path, 'utf8'));

View file

@ -19,12 +19,24 @@ export async function createFailureIssue(
) {
const title = `Failing test: ${failure.classname} - ${failure.name}`;
// Github API body length maximum is 65536 characters
// Let's keep consistency with Mocha output that is truncated to 8192 characters
const failureMaxCharacters = 8192;
const failureBody =
failure.failure.length <= failureMaxCharacters
? failure.failure
: [
failure.failure.substring(0, failureMaxCharacters),
`[report_failure] output truncated to ${failureMaxCharacters} characters`,
].join('\n');
const body = updateIssueMetadata(
[
'A test failed on a tracked branch',
'',
'```',
failure.failure,
failureBody,
'```',
'',
`First failure: [CI Build - ${branch}](${buildUrl})`,

View file

@ -253,7 +253,7 @@ exports[`guide cards snapshots should render all cards 1`] = `
Object {
"navigateTo": Object {
"appId": "integrations",
"path": "/detail/cloud_security_posture/overview",
"path": "/detail/cloud_security_posture/overview?integration=cspm",
},
"order": 9,
"solution": "security",

View file

@ -169,7 +169,7 @@ export const guideCards: GuideCardConstants[] = [
),
navigateTo: {
appId: 'integrations',
path: '/detail/cloud_security_posture/overview',
path: '/detail/cloud_security_posture/overview?integration=cspm',
},
telemetryId: 'onboarding--security--cloud',
order: 9,

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
import { getMappingConflictsInfo } from '.';
import { getMappingConflictsInfo, fieldSupportsMatches } from '.';
describe('Helpers', () => {
describe('getMappingConflictsInfo', () => {
@ -143,4 +143,42 @@ describe('Helpers', () => {
]);
});
});
describe('fieldSupportsMatches', () => {
test('it returns true if esTypes is keyword', () => {
expect(
fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['keyword'] })
).toBeTruthy();
});
test('it returns true if one of the esTypes is kibana type string and another is not', () => {
expect(
fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['keyword', 'object'] })
).toBeTruthy();
});
test('it returns true if one of the esTypes is keyword', () => {
expect(
fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['keyword', 'unmapped'] })
).toBeTruthy();
});
test('it returns true if one of the esTypes is text', () => {
expect(
fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['text', 'unmapped'] })
).toBeTruthy();
});
test('it returns true if all of the esTypes is map to kibana type string', () => {
expect(
fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['text', 'keyword'] })
).toBeTruthy();
});
test('it returns false if none of the esTypes map to kibana type string', () => {
expect(
fieldSupportsMatches({ name: 'field', type: 'conflict', esTypes: ['bool', 'unmapped'] })
).toBeFalsy();
});
});
});

View file

@ -35,6 +35,7 @@ import {
getDataViewFieldSubtypeNested,
isDataViewFieldSubtypeNested,
} from '@kbn/es-query';
import { castEsToKbnFieldTypeName, KBN_FIELD_TYPES } from '@kbn/field-types';
import {
ALL_OPERATORS,
@ -676,8 +677,13 @@ export const getEntryOnOperatorChange = (
}
};
const fieldSupportsMatches = (field: DataViewFieldBase) => {
return field.type === 'string';
export const isKibanaStringType = (type: string) => {
const kbnFieldType = castEsToKbnFieldTypeName(type);
return kbnFieldType === KBN_FIELD_TYPES.STRING;
};
export const fieldSupportsMatches = (field: DataViewFieldBase) => {
return field.esTypes?.some(isKibanaStringType);
};
/**

View file

@ -26,6 +26,10 @@ import {
EXCEPTION_LIST_NAMESPACE_AGNOSTIC,
} from '@kbn/securitysolution-list-constants';
export interface DataViewField extends DataViewFieldBase {
conflictDescriptions?: Record<string, string[]>;
}
export interface OperatorOption {
message: string;
value: string;
@ -35,7 +39,7 @@ export interface OperatorOption {
export interface FormattedBuilderEntry {
id: string;
field: DataViewFieldBase | undefined;
field: DataViewField | undefined;
operator: OperatorOption;
value: string | string[] | undefined;
nested: 'parent' | 'child' | undefined;
@ -117,7 +121,3 @@ export const exceptionListAgnosticSavedObjectType = EXCEPTION_LIST_NAMESPACE_AGN
export type SavedObjectType =
| typeof EXCEPTION_LIST_NAMESPACE
| typeof EXCEPTION_LIST_NAMESPACE_AGNOSTIC;
export interface DataViewField extends DataViewFieldBase {
conflictDescriptions?: Record<string, string[]>;
}

View file

@ -16,7 +16,8 @@
"@kbn/securitysolution-io-ts-list-types",
"@kbn/securitysolution-io-ts-utils",
"@kbn/securitysolution-list-constants",
"@kbn/securitysolution-utils"
"@kbn/securitysolution-utils",
"@kbn/field-types"
],
"exclude": [
"target/**/*",

View file

@ -27,4 +27,5 @@ export {
asyncForEach,
asyncForEachWithLimit,
} from './src/iteration';
export { ensureDeepObject } from './src/ensure_deep_object';
export { Semaphore } from './src/semaphore';

View file

@ -143,3 +143,81 @@ test('array composed of flat objects', () => {
expect(ensureDeepObject(arr)).toEqual([{ c: { d: 2 } }, { e: { f: 3 } }]);
});
describe('forbidden patterns', () => {
describe('first pattern', () => {
test('throws when finding the first pattern within an object', () => {
const obj = {
foo: {
hello: 'dolly',
'bar.__proto__': { yours: 'mine' },
},
};
expect(() => ensureDeepObject(obj)).toThrowErrorMatchingInlineSnapshot(
`"Forbidden path detected: foo.bar.__proto__"`
);
});
test('throws when finding the first pattern within an array', () => {
const obj = {
array: [
'hello',
{
'bar.__proto__': { their: 'mine' },
},
],
};
expect(() => ensureDeepObject(obj)).toThrowErrorMatchingInlineSnapshot(
`"Forbidden path detected: array.1.bar.__proto__"`
);
});
});
describe('second pattern', () => {
test('throws when finding the first pattern within an object', () => {
const obj = {
foo: {
hello: 'dolly',
'bar.constructor.prototype': { foo: 'bar' },
},
};
expect(() => ensureDeepObject(obj)).toThrowErrorMatchingInlineSnapshot(
`"Forbidden path detected: foo.bar.constructor.prototype"`
);
});
test('throws when finding the first pattern within a nested object', () => {
const obj = {
foo: {
hello: 'dolly',
'bar.constructor': {
main: 'mine',
prototype: 'nope',
},
},
};
expect(() => ensureDeepObject(obj)).toThrowErrorMatchingInlineSnapshot(
`"Forbidden path detected: foo.bar.constructor.prototype"`
);
});
test('throws when finding the first pattern within an array', () => {
const obj = {
array: [
'hello',
{
'bar.constructor.prototype': { foo: 'bar' },
},
],
};
expect(() => ensureDeepObject(obj)).toThrowErrorMatchingInlineSnapshot(
`"Forbidden path detected: array.1.bar.constructor.prototype"`
);
});
});
});

View file

@ -6,56 +6,61 @@
* Side Public License, v 1.
*/
//
// THIS IS A DIRECT COPY OF
// 'packages/kbn-config/src/raw/ensure_deep_object.ts'
// BECAUSE THAT IS BLOCKED FOR IMPORTING BY OUR LINTER.
//
// IF THAT IS EXPOSED, WE SHOULD USE IT RATHER THAN CLONE IT.
//
/* eslint-disable @typescript-eslint/no-explicit-any */
// ^ Disabling the rule for the entire file because of the complexity to type this
const FORBIDDEN_PATTERNS = ['__proto__', 'constructor.prototype'];
const separator = '.';
/**
* Recursively traverses through the object's properties and expands ones with
* dot-separated names into nested objects (eg. { a.b: 'c'} -> { a: { b: 'c' }).
* @param obj Object to traverse through.
* @param path The current path of the traversal
* @returns Same object instance with expanded properties.
*/
export function ensureDeepObject(obj: any): any {
export function ensureDeepObject(obj: any, path: string[] = []): any {
assertValidPath(path);
if (obj == null || typeof obj !== 'object') {
return obj;
}
if (Array.isArray(obj)) {
return obj.map((item) => ensureDeepObject(item));
return obj.map((item, index) => ensureDeepObject(item, [...path, `${index}`]));
}
return Object.keys(obj).reduce((fullObject, propertyKey) => {
const propertyValue = obj[propertyKey];
if (!propertyKey.includes(separator)) {
fullObject[propertyKey] = ensureDeepObject(propertyValue);
const propertySplits = propertyKey.split(separator);
if (propertySplits.length === 1) {
fullObject[propertyKey] = ensureDeepObject(propertyValue, [...path, propertyKey]);
} else {
walk(fullObject, propertyKey.split(separator), propertyValue);
walk(fullObject, propertySplits, propertyValue, path);
}
return fullObject;
}, {} as any);
}
function walk(obj: any, keys: string[], value: any) {
function walk(obj: any, keys: string[], value: any, path: string[]) {
assertValidPath([...path, ...keys]);
const key = keys.shift()!;
if (keys.length === 0) {
obj[key] = value;
return;
}
if (obj[key] === undefined) {
if (!obj.hasOwnProperty(key)) {
obj[key] = {};
}
walk(obj[key], keys, ensureDeepObject(value));
walk(obj[key], keys, ensureDeepObject(value, [...path, key, ...keys]), [...path, key]);
}
const assertValidPath = (path: string[]) => {
const flat = path.join('.');
FORBIDDEN_PATTERNS.forEach((pattern) => {
if (flat.includes(pattern)) {
throw new Error(`Forbidden path detected: ${flat}`);
}
});
};

View file

@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
require('@kbn/babel-register').install();
require('./apm')(process.env.ELASTIC_APM_SERVICE_NAME || 'kibana-proxy');
require('../setup_node_env');
require('./apm')(process.env.ELASTIC_APM_SERVICE_NAME || 'kibana-proxy');
require('./cli');

View file

@ -6,7 +6,7 @@
* Side Public License, v 1.
*/
require('./apm')();
require('../setup_node_env/dist');
require('./apm')();
require('../setup_node_env/root');
require('./cli');

View file

@ -17,7 +17,6 @@
"@kbn/config",
"@kbn/dev-utils",
"@kbn/apm-config-loader",
"@kbn/babel-register",
],
"exclude": [
"target/**/*",

View file

@ -0,0 +1,143 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import fetch from 'node-fetch';
import pRetry from 'p-retry';
import { REPO_ROOT } from '@kbn/repo-info';
import { ToolingLog } from '@kbn/tooling-log';
import { FetchAgentVersionsList } from './fetch_agent_versions_list';
import { Build, Config, write } from '../lib';
jest.mock('node-fetch');
jest.mock('p-retry');
jest.mock('../lib');
const config = new Config(
true,
{
version: '8.0.0',
engines: {
node: '*',
},
workspaces: {
packages: [],
},
} as any,
'1.2.3',
REPO_ROOT,
{
buildNumber: 1234,
buildSha: 'abcd1234',
buildVersion: '8.0.0',
},
false,
false,
null,
'',
'',
false,
true
);
const mockedFetch = fetch as jest.MockedFunction<typeof fetch>;
const mockedPRetry = pRetry as jest.MockedFunction<typeof pRetry>;
const mockedWrite = write as jest.MockedFunction<typeof write>;
const mockedBuild = new Build(config);
mockedPRetry.mockImplementation((fn: any) => {
return fn();
});
const processEnv = process.env;
describe('FetchAgentVersionsList', () => {
beforeEach(() => {
process.env = {
...processEnv,
// Ensure these tests can run in PR builds
BUILDKITE_PULL_REQUEST: undefined,
};
mockedFetch.mockReset();
(mockedBuild.resolvePath as jest.Mock<any>).mockReset();
mockedWrite.mockReset();
});
afterEach(() => {
process.env = processEnv;
});
describe('when BUILDKITE_PULL_REQUEST is set', () => {
it('does not run task', async () => {
process.env.BUILDKITE_PULL_REQUEST = '1234';
await FetchAgentVersionsList.run(config, new ToolingLog(), mockedBuild);
expect(mockedFetch).not.toHaveBeenCalled();
});
});
describe('when valid JSON is returned from versions endpoint', () => {
it('does not throw', async () => {
mockedFetch.mockResolvedValueOnce({
status: 200,
text: jest.fn().mockResolvedValueOnce(
JSON.stringify([
[
{
title: 'Elastic Agent 8.0.0',
version_number: '8.0.0',
},
{
title: 'Elastic Agent 8.0.1',
version_number: '8.0.1',
},
],
])
),
} as any);
await FetchAgentVersionsList.run(config, new ToolingLog(), mockedBuild);
expect(mockedWrite).toHaveBeenCalledTimes(1);
});
});
describe('when a network error is thrown', () => {
it('throws', async () => {
mockedFetch.mockResolvedValueOnce({
status: 503,
text: jest.fn().mockResolvedValueOnce('Gateway timeout'),
} as any);
try {
await FetchAgentVersionsList.run(config, new ToolingLog(), mockedBuild);
} catch (error) {
expect(error).toBeTruthy();
expect(mockedWrite).not.toHaveBeenCalled();
}
});
});
describe('when invalid json is returned from versions endpoint', () => {
it('throws', async () => {
mockedFetch.mockResolvedValueOnce({
status: 200,
text: jest.fn().mockResolvedValueOnce('not json'),
} as any);
try {
await FetchAgentVersionsList.run(config, new ToolingLog(), mockedBuild);
} catch (error) {
expect(error).toBeTruthy();
expect(mockedWrite).not.toHaveBeenCalled();
}
});
});
});

View file

@ -7,24 +7,34 @@
*/
import fetch from 'node-fetch';
import pRetry from 'p-retry';
import { ToolingLog } from '@kbn/tooling-log';
import { write, Task } from '../lib';
// Endpoint maintained by the web-team and hosted on the elastic website
const PRODUCT_VERSIONS_URL = 'https://www.elastic.co/api/product_versions';
const isPr = () =>
!!process.env.BUILDKITE_PULL_REQUEST && process.env.BUILDKITE_PULL_REQUEST !== 'false';
const getAvailableVersions = async (log: ToolingLog) => {
const options = {
headers: {
'Content-Type': 'application/json',
},
};
// Endpoint maintained by the web-team and hosted on the elastic website
// See https://github.com/elastic/website-development/issues/9331
const url = 'https://www.elastic.co/api/product_versions';
try {
log.info('Fetching Elastic Agent versions list');
const results = await fetch(url, options);
log.info('Fetching Elastic Agent versions list');
const jsonBody = await results.json();
try {
const results = await pRetry(() => fetch(PRODUCT_VERSIONS_URL, options), { retries: 3 });
const rawBody = await results.text();
if (results.status >= 400) {
throw new Error(`Status code ${results.status} received from versions API: ${rawBody}`);
}
const jsonBody = JSON.parse(rawBody);
const versions: string[] = (jsonBody.length ? jsonBody[0] : [])
.filter((item: any) => item?.title?.includes('Elastic Agent'))
@ -33,8 +43,18 @@ const getAvailableVersions = async (log: ToolingLog) => {
log.info(`Retrieved available versions`);
return versions;
} catch (error) {
log.warning(`Failed to fetch versions list`);
log.warning(error);
const errorMessage = 'Failed to fetch Elastic Agent versions list';
if (isPr()) {
// For PR jobs, just log the error as a warning and continue
log.warning(errorMessage);
log.warning(error);
} else {
// For non-PR jobs like nightly builds, log the error to stderror and throw
// to ensure the build fails
log.error(errorMessage);
throw new Error(error);
}
}
return [];
};
@ -44,6 +64,11 @@ export const FetchAgentVersionsList: Task = {
description: 'Build list of available Elastic Agent versions for Fleet UI',
async run(config, log, build) {
// Agent version list task is skipped for PR's, so as not to overwhelm the versions API
if (isPr()) {
return;
}
const versionsList = await getAvailableVersions(log);
const AGENT_VERSION_BUILD_FILE = 'x-pack/plugins/fleet/target/agent_versions_list.json';

View file

@ -16,6 +16,7 @@
import React, { useEffect, useState } from 'react';
import useMount from 'react-use/lib/useMount';
import useAsync from 'react-use/lib/useAsync';
import {
EuiFlyoutHeader,
@ -35,7 +36,7 @@ import {
EuiSwitch,
EuiTextColor,
} from '@elastic/eui';
import { DataViewListItem, DataView, DataViewField } from '@kbn/data-views-plugin/common';
import { DataViewField } from '@kbn/data-views-plugin/common';
import {
LazyDataViewPicker,
LazyFieldPicker,
@ -46,13 +47,13 @@ import { ControlGroupStrings } from '../control_group_strings';
import {
ControlEmbeddable,
ControlWidth,
DataControlFieldRegistry,
DataControlInput,
IEditableControlFactory,
} from '../../types';
import { CONTROL_WIDTH_OPTIONS } from './editor_constants';
import { pluginServices } from '../../services';
import { getDataControlFieldRegistry } from './data_control_editor_tools';
interface EditControlProps {
embeddable?: ControlEmbeddable<DataControlInput>;
isCreate: boolean;
@ -70,12 +71,6 @@ interface EditControlProps {
onTypeEditorChange: (partial: Partial<DataControlInput>) => void;
}
interface ControlEditorState {
dataViewListItems: DataViewListItem[];
selectedDataView?: DataView;
selectedField?: DataViewField;
}
const FieldPicker = withSuspense(LazyFieldPicker, null);
const DataViewPicker = withSuspense(LazyDataViewPicker, null);
@ -99,59 +94,62 @@ export const ControlEditor = ({
dataViews: { getIdsWithTitle, getDefaultId, get },
controls: { getControlFactory },
} = pluginServices.getServices();
const [state, setState] = useState<ControlEditorState>({
dataViewListItems: [],
});
const [defaultTitle, setDefaultTitle] = useState<string>();
const [currentTitle, setCurrentTitle] = useState(title);
const [currentTitle, setCurrentTitle] = useState(title ?? '');
const [currentWidth, setCurrentWidth] = useState(width);
const [currentGrow, setCurrentGrow] = useState(grow);
const [controlEditorValid, setControlEditorValid] = useState(false);
const [selectedField, setSelectedField] = useState<string | undefined>(
embeddable ? embeddable.getInput().fieldName : undefined
);
const [fieldRegistry, setFieldRegistry] = useState<DataControlFieldRegistry>();
useEffect(() => {
(async () => {
if (state.selectedDataView?.id) {
setFieldRegistry(await getDataControlFieldRegistry(await get(state.selectedDataView.id)));
}
})();
}, [state.selectedDataView?.id, get]);
const [selectedDataViewId, setSelectedDataViewId] = useState<string>();
useMount(() => {
let mounted = true;
if (selectedField) setDefaultTitle(selectedField);
(async () => {
const dataViewListItems = await getIdsWithTitle();
if (!mounted) return;
const initialId =
embeddable?.getInput().dataViewId ?? getRelevantDataViewId?.() ?? (await getDefaultId());
let dataView: DataView | undefined;
if (initialId) {
onTypeEditorChange({ dataViewId: initialId });
dataView = await get(initialId);
setSelectedDataViewId(initialId);
}
if (!mounted) return;
setState((s) => ({
...s,
selectedDataView: dataView,
dataViewListItems,
}));
})();
return () => {
mounted = false;
};
});
const { loading: dataViewListLoading, value: dataViewListItems = [] } = useAsync(() => {
return getIdsWithTitle();
});
const {
loading: dataViewLoading,
value: { selectedDataView, fieldRegistry } = {
selectedDataView: undefined,
fieldRegistry: undefined,
},
} = useAsync(async () => {
if (!selectedDataViewId) {
return;
}
const dataView = await get(selectedDataViewId);
const registry = await getDataControlFieldRegistry(dataView);
return {
selectedDataView: dataView,
fieldRegistry: registry,
};
}, [selectedDataViewId]);
useEffect(
() => setControlEditorValid(Boolean(selectedField) && Boolean(state.selectedDataView)),
[selectedField, setControlEditorValid, state.selectedDataView]
() => setControlEditorValid(Boolean(selectedField) && Boolean(selectedDataView)),
[selectedField, setControlEditorValid, selectedDataView]
);
const { selectedDataView: dataView } = state;
const controlType =
selectedField && fieldRegistry && fieldRegistry[selectedField].compatibleControlTypes[0];
const factory = controlType && getControlFactory(controlType);
@ -172,46 +170,45 @@ export const ControlEditor = ({
<EuiForm>
<EuiFormRow label={ControlGroupStrings.manageControl.getDataViewTitle()}>
<DataViewPicker
dataViews={state.dataViewListItems}
selectedDataViewId={dataView?.id}
dataViews={dataViewListItems}
selectedDataViewId={selectedDataViewId}
onChangeDataViewId={(dataViewId) => {
setLastUsedDataViewId?.(dataViewId);
if (dataViewId === dataView?.id) return;
if (dataViewId === selectedDataViewId) return;
onTypeEditorChange({ dataViewId });
setSelectedField(undefined);
get(dataViewId).then((newDataView) => {
setState((s) => ({ ...s, selectedDataView: newDataView }));
});
setSelectedDataViewId(dataViewId);
}}
trigger={{
label:
state.selectedDataView?.getName() ??
selectedDataView?.getName() ??
ControlGroupStrings.manageControl.getSelectDataViewMessage(),
}}
selectableProps={{ isLoading: dataViewListLoading }}
/>
</EuiFormRow>
<EuiFormRow label={ControlGroupStrings.manageControl.getFieldTitle()}>
<FieldPicker
filterPredicate={(field: DataViewField) => {
return Boolean(fieldRegistry?.[field.name]);
}}
selectedFieldName={selectedField}
dataView={dataView}
onSelectField={(field) => {
onTypeEditorChange({
fieldName: field.name,
});
const newDefaultTitle = field.displayName ?? field.name;
setDefaultTitle(newDefaultTitle);
setSelectedField(field.name);
if (!currentTitle || currentTitle === defaultTitle) {
setCurrentTitle(newDefaultTitle);
updateTitle(newDefaultTitle);
}
}}
/>
</EuiFormRow>
{fieldRegistry && (
<EuiFormRow label={ControlGroupStrings.manageControl.getFieldTitle()}>
<FieldPicker
filterPredicate={(field: DataViewField) => Boolean(fieldRegistry[field.name])}
selectedFieldName={selectedField}
dataView={selectedDataView}
onSelectField={(field) => {
onTypeEditorChange({
fieldName: field.name,
});
const newDefaultTitle = field.displayName ?? field.name;
setDefaultTitle(newDefaultTitle);
setSelectedField(field.name);
if (!currentTitle || currentTitle === defaultTitle) {
setCurrentTitle(newDefaultTitle);
updateTitle(newDefaultTitle);
}
}}
selectableProps={{ isLoading: dataViewListLoading || dataViewLoading }}
/>
</EuiFormRow>
)}
<EuiFormRow label={ControlGroupStrings.manageControl.getControlTypeTitle()}>
{factory ? (
<EuiFlexGroup alignItems="center" gutterSize="xs">
@ -239,6 +236,7 @@ export const ControlEditor = ({
}}
/>
</EuiFormRow>
<EuiFormRow label={ControlGroupStrings.manageControl.getWidthInputTitle()}>
<>
<EuiButtonGroup
@ -273,7 +271,7 @@ export const ControlEditor = ({
<CustomSettings
onChange={onTypeEditorChange}
initialInput={embeddable?.getInput()}
fieldType={fieldRegistry[selectedField].field.type}
fieldType={fieldRegistry?.[selectedField].field.type}
/>
</EuiFormRow>
)}

View file

@ -11,7 +11,7 @@ import { memoize } from 'lodash';
import { DataView } from '@kbn/data-views-plugin/common';
import { pluginServices } from '../../services';
import { DataControlField, DataControlFieldRegistry, IEditableControlFactory } from '../../types';
import { DataControlFieldRegistry, IEditableControlFactory } from '../../types';
export const getDataControlFieldRegistry = memoize(
async (dataView: DataView) => {
@ -30,20 +30,19 @@ const loadFieldRegistryFromDataView = async (
const controlFactories = getControlTypes().map(
(controlType) => getControlFactory(controlType) as IEditableControlFactory
);
const fieldRegistry: DataControlFieldRegistry = dataView.fields
.getAll()
.reduce((registry, field) => {
const test: DataControlField = { field, compatibleControlTypes: [] };
const fieldRegistry: DataControlFieldRegistry = {};
return new Promise<DataControlFieldRegistry>((resolve) => {
for (const field of dataView.fields.getAll()) {
const compatibleControlTypes = [];
for (const factory of controlFactories) {
if (factory.isFieldCompatible) {
factory.isFieldCompatible(test);
if (factory.isFieldCompatible && factory.isFieldCompatible(field)) {
compatibleControlTypes.push(factory.type);
}
}
if (test.compatibleControlTypes.length === 0) {
return { ...registry };
if (compatibleControlTypes.length > 0) {
fieldRegistry[field.name] = { field, compatibleControlTypes };
}
return { ...registry, [field.name]: test };
}, {});
return fieldRegistry;
}
resolve(fieldRegistry);
});
};

View file

@ -9,6 +9,7 @@
import deepEqual from 'fast-deep-equal';
import { i18n } from '@kbn/i18n';
import { DataViewField } from '@kbn/data-views-plugin/common';
import { lazyLoadReduxEmbeddablePackage } from '@kbn/presentation-util-plugin/public';
import { EmbeddableFactoryDefinition, IContainer } from '@kbn/embeddable-plugin/public';
@ -20,8 +21,8 @@ import {
OptionsListEmbeddableInput,
OPTIONS_LIST_CONTROL,
} from '../../../common/options_list/types';
import { ControlEmbeddable, DataControlField, IEditableControlFactory } from '../../types';
import { OptionsListEditorOptions } from '../components/options_list_editor_options';
import { ControlEmbeddable, IEditableControlFactory } from '../../types';
export class OptionsListEmbeddableFactory
implements EmbeddableFactoryDefinition, IEditableControlFactory<OptionsListEmbeddableInput>
@ -54,15 +55,13 @@ export class OptionsListEmbeddableFactory
return newInput;
};
public isFieldCompatible = (dataControlField: DataControlField) => {
if (
!dataControlField.field.spec.scripted &&
((dataControlField.field.aggregatable && dataControlField.field.type === 'string') ||
dataControlField.field.type === 'boolean' ||
dataControlField.field.type === 'ip')
) {
dataControlField.compatibleControlTypes.push(this.type);
}
public isFieldCompatible = (field: DataViewField) => {
return (
!field.spec.scripted &&
((field.aggregatable && field.type === 'string') ||
field.type === 'boolean' ||
field.type === 'ip')
);
};
public controlEditorOptionsComponent = OptionsListEditorOptions;

View file

@ -10,6 +10,7 @@ import deepEqual from 'fast-deep-equal';
import { EmbeddableFactoryDefinition, IContainer } from '@kbn/embeddable-plugin/public';
import { lazyLoadReduxEmbeddablePackage } from '@kbn/presentation-util-plugin/public';
import { DataViewField } from '@kbn/data-views-plugin/common';
import { i18n } from '@kbn/i18n';
import {
@ -20,7 +21,7 @@ import {
RangeSliderEmbeddableInput,
RANGE_SLIDER_CONTROL,
} from '../../../common/range_slider/types';
import { ControlEmbeddable, DataControlField, IEditableControlFactory } from '../../types';
import { ControlEmbeddable, IEditableControlFactory } from '../../types';
export class RangeSliderEmbeddableFactory
implements EmbeddableFactoryDefinition, IEditableControlFactory<RangeSliderEmbeddableInput>
@ -68,10 +69,8 @@ export class RangeSliderEmbeddableFactory
return newInput;
};
public isFieldCompatible = (dataControlField: DataControlField) => {
if (dataControlField.field.aggregatable && dataControlField.field.type === 'number') {
dataControlField.compatibleControlTypes.push(this.type);
}
public isFieldCompatible = (field: DataViewField) => {
return field.aggregatable && field.type === 'number';
};
public inject = createRangeSliderInject();

View file

@ -46,13 +46,14 @@ export type ControlEmbeddable<
/**
* Control embeddable editor types
*/
export interface IEditableControlFactory<T extends ControlInput = ControlInput> {
export interface IEditableControlFactory<T extends ControlInput = ControlInput>
extends Pick<EmbeddableFactory, 'type'> {
controlEditorOptionsComponent?: (props: ControlEditorProps<T>) => JSX.Element;
presaveTransformFunction?: (
newState: Partial<T>,
embeddable?: ControlEmbeddable<T>
) => Partial<T>;
isFieldCompatible?: (dataControlField: DataControlField) => void; // reducer
isFieldCompatible?: (field: DataViewField) => boolean;
}
export interface ControlEditorProps<T extends ControlInput = ControlInput> {

View file

@ -8,6 +8,7 @@
import { getKbnServerError, reportServerError } from '@kbn/kibana-utils-plugin/server';
import { CoreSetup } from '@kbn/core/server';
import { errors } from '@elastic/elasticsearch';
export const setupOptionsListClusterSettingsRoute = ({ http }: CoreSetup) => {
const router = http.createRouter();
@ -39,6 +40,17 @@ export const setupOptionsListClusterSettingsRoute = ({ http }: CoreSetup) => {
},
});
} catch (e) {
if (e instanceof errors.ResponseError && e.body.error.type === 'security_exception') {
/**
* in cases where the user does not have the 'monitor' permission this check will fail. In these cases, we will
* fall back to assume that the allowExpensiveQueries setting is on, because it defaults to true.
*/
return response.ok({
body: {
allowExpensiveQueries: true,
},
});
}
const kbnErr = getKbnServerError(e);
return reportServerError(response, kbnErr);
}

View file

@ -7,117 +7,31 @@
*/
import { mapSpatialFilter } from './map_spatial_filter';
import { mapFilter } from '../map_filter';
import { FilterMeta, Filter, FILTERS } from '@kbn/es-query';
describe('mapSpatialFilter()', () => {
test('should return the key for matching multi polygon filter', async () => {
describe('mapSpatialFilter', () => {
test('should set meta type field', async () => {
const filter = {
meta: {
key: 'location',
alias: 'my spatial filter',
type: FILTERS.SPATIAL_FILTER,
} as FilterMeta,
query: {
bool: {
should: [
{
geo_polygon: {
geoCoordinates: { points: [] },
},
},
],
},
},
query: {},
} as Filter;
const result = mapSpatialFilter(filter);
expect(result).toHaveProperty('key', 'location');
expect(result).toHaveProperty('value', '');
expect(result).toHaveProperty('type', FILTERS.SPATIAL_FILTER);
});
test('should return the key for matching polygon filter', async () => {
const filter = {
meta: {
key: 'location',
alias: 'my spatial filter',
type: FILTERS.SPATIAL_FILTER,
} as FilterMeta,
geo_polygon: {
geoCoordinates: { points: [] },
},
} as Filter;
const result = mapSpatialFilter(filter);
expect(result).toHaveProperty('key', 'location');
expect(result).toHaveProperty('value', '');
expect(result).toHaveProperty('type', FILTERS.SPATIAL_FILTER);
});
test('should return the key for matching multi field filter', async () => {
const filter = {
meta: {
alias: 'my spatial filter',
isMultiIndex: true,
type: FILTERS.SPATIAL_FILTER,
} as FilterMeta,
query: {
bool: {
should: [
{
bool: {
must: [
{
exists: {
field: 'geo.coordinates',
},
},
{
geo_distance: {
distance: '1000km',
'geo.coordinates': [120, 30],
},
},
],
},
},
{
bool: {
must: [
{
exists: {
field: 'location',
},
},
{
geo_distance: {
distance: '1000km',
location: [120, 30],
},
},
],
},
},
],
},
},
} as Filter;
const result = mapSpatialFilter(filter);
expect(result).toHaveProperty('key', 'query');
expect(result).toHaveProperty('value', '');
expect(result).toHaveProperty('type', FILTERS.SPATIAL_FILTER);
expect(result).toHaveProperty('key', undefined);
expect(result).toHaveProperty('value', undefined);
});
test('should return undefined for none matching', async () => {
const filter = {
meta: {
key: 'location',
alias: 'my spatial filter',
alias: 'my non-spatial filter',
} as FilterMeta,
geo_polygon: {
geoCoordinates: { points: [] },
},
query: {},
} as Filter;
try {
@ -127,3 +41,17 @@ describe('mapSpatialFilter()', () => {
}
});
});
describe('mapFilter', () => {
test('should set key and value properties to undefined', async () => {
const before = {
meta: { type: FILTERS.SPATIAL_FILTER } as FilterMeta,
query: {},
} as Filter;
const after = mapFilter(before);
expect(after).toHaveProperty('meta');
expect(after.meta).toHaveProperty('key', undefined);
expect(after.meta).toHaveProperty('value', undefined);
});
});

View file

@ -10,30 +10,17 @@ import { Filter, FILTERS } from '@kbn/es-query';
// Use mapSpatialFilter mapper to avoid bloated meta with value and params for spatial filters.
export const mapSpatialFilter = (filter: Filter) => {
if (
filter.meta &&
filter.meta.key &&
filter.meta.alias &&
filter.meta.type === FILTERS.SPATIAL_FILTER
) {
if (filter.meta?.type === FILTERS.SPATIAL_FILTER) {
return {
key: filter.meta.key,
type: filter.meta.type,
value: '',
// spatial filters support multiple fields across multiple data views
// do not provide "key" since filter does not provide a single field
key: undefined,
// default mapper puts stringified filter in "value"
// do not provide "value" to avoid bloating URL
value: undefined,
};
}
if (
filter.meta &&
filter.meta.type === FILTERS.SPATIAL_FILTER &&
filter.meta.isMultiIndex &&
filter.query?.bool?.should
) {
return {
key: 'query',
type: filter.meta.type,
value: '',
};
}
throw filter;
};

View file

@ -59,6 +59,9 @@ const currentDocumentSelector = (state: PreviewState) => state.documents[state.c
const currentDocumentIsLoadingSelector = (state: PreviewState) => state.isLoadingDocuments;
const ScriptFieldComponent = ({ existingConcreteFields, links, placeholder }: Props) => {
const {
validation: { setScriptEditorValidation },
} = useFieldPreviewContext();
const monacoEditor = useRef<monaco.editor.IStandaloneCodeEditor | null>(null);
const editorValidationSubscription = useRef<Subscription>();
const fieldCurrentValue = useRef<string>('');
@ -143,7 +146,7 @@ const ScriptFieldComponent = ({ existingConcreteFields, links, placeholder }: Pr
editorValidationSubscription.current = PainlessLang.validation$().subscribe(
({ isValid, isValidating, errors }) => {
controller.setScriptEditorValidation({
setScriptEditorValidation({
isValid,
isValidating,
message: errors[0]?.message ?? null,
@ -151,7 +154,7 @@ const ScriptFieldComponent = ({ existingConcreteFields, links, placeholder }: Pr
}
);
},
[controller]
[setScriptEditorValidation]
);
const updateMonacoMarkers = useCallback((markers: monaco.editor.IMarkerData[]) => {

View file

@ -75,8 +75,6 @@ const documentsSelector = (state: PreviewState) => {
};
};
const scriptEditorValidationSelector = (state: PreviewState) => state.scriptEditorValidation;
export const FieldPreviewProvider: FunctionComponent<{ controller: PreviewController }> = ({
controller,
children,
@ -121,6 +119,12 @@ export const FieldPreviewProvider: FunctionComponent<{ controller: PreviewContro
/** The parameters required for the Painless _execute API */
const [params, setParams] = useState<Params>(defaultParams);
const [scriptEditorValidation, setScriptEditorValidation] = useState<{
isValidating: boolean;
isValid: boolean;
message: string | null;
}>({ isValidating: false, isValid: true, message: null });
/** Flag to show/hide the preview panel */
const [isPanelVisible, setIsPanelVisible] = useState(true);
/** Flag to indicate if we are loading document from cluster */
@ -133,10 +137,6 @@ export const FieldPreviewProvider: FunctionComponent<{ controller: PreviewContro
const { currentDocument, currentDocIndex, currentDocId, totalDocs, currentIdx } =
useStateSelector(controller.state$, documentsSelector);
const scriptEditorValidation = useStateSelector(
controller.state$,
scriptEditorValidationSelector
);
let isPreviewAvailable = true;
@ -513,6 +513,9 @@ export const FieldPreviewProvider: FunctionComponent<{ controller: PreviewContro
isVisible: isPanelVisible,
setIsVisible: setIsPanelVisible,
},
validation: {
setScriptEditorValidation,
},
reset,
}),
[

View file

@ -99,9 +99,11 @@ export class PreviewController {
}
};
/* disabled while investigating issues with painless script editor
setScriptEditorValidation = (scriptEditorValidation: PreviewState['scriptEditorValidation']) => {
this.updateState({ scriptEditorValidation });
};
*/
setCustomId = (customId?: string) => {
this.updateState({ customId });

View file

@ -133,6 +133,11 @@ export interface Context {
isLastDoc: boolean;
};
reset: () => void;
validation: {
setScriptEditorValidation: React.Dispatch<
React.SetStateAction<{ isValid: boolean; isValidating: boolean; message: string | null }>
>;
};
}
export type PainlessExecuteContext =

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