diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c91d1a702b7ec..168db2c4efb84 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -349,6 +349,21 @@ /x-pack/test/case_api_integration @elastic/security-threat-hunting /x-pack/plugins/lists @elastic/security-detections-response +## Security Solution sub teams - security-onboarding-and-lifecycle-mgt +/x-pack/plugins/security_solution/public/management/ @elastic/security-onboarding-and-lifecycle-mgt +/x-pack/plugins/security_solution/public/common/lib/endpoint*/ @elastic/security-onboarding-and-lifecycle-mgt +/x-pack/plugins/security_solution/public/common/components/endpoint/ @elastic/security-onboarding-and-lifecycle-mgt +/x-pack/plugins/security_solution/common/endpoint/ @elastic/security-onboarding-and-lifecycle-mgt +/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/ @elastic/security-onboarding-and-lifecycle-mgt +/x-pack/plugins/security_solution/server/endpoint/routes/actions/ @elastic/security-onboarding-and-lifecycle-mgt +/x-pack/plugins/security_solution/server/endpoint/routes/metadata/ @elastic/security-onboarding-and-lifecycle-mgt +/x-pack/plugins/security_solution/server/endpoint/lib/policy/ @elastic/security-onboarding-and-lifecycle-mgt +/x-pack/plugins/security_solution/server/lib/license/ @elastic/security-onboarding-and-lifecycle-mgt +/x-pack/plugins/security_solution/server/fleet_integration/ @elastic/security-onboarding-and-lifecycle-mgt +/x-pack/plugins/security_solution/scripts/endpoint/event_filters/ @elastic/security-onboarding-and-lifecycle-mgt +/x-pack/plugins/security_solution/scripts/endpoint/trusted_apps/ @elastic/security-onboarding-and-lifecycle-mgt +/x-pack/test/security_solution_endpoint/apps/endpoint/ @elastic/security-onboarding-and-lifecycle-mgt + # Security Intelligence And Analytics /x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules @elastic/security-intelligence-analytics diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index c95a818ac47e4..e26c2ec09acf7 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -10,15 +10,15 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # Fetch Node.js rules http_archive( name = "build_bazel_rules_nodejs", - sha256 = "0fa2d443571c9e02fcb7363a74ae591bdcce2dd76af8677a95965edf329d778a", - urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/3.6.0/rules_nodejs-3.6.0.tar.gz"], + sha256 = "8f5f192ba02319254aaf2cdcca00ec12eaafeb979a80a1e946773c520ae0a2c9", + urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/3.7.0/rules_nodejs-3.7.0.tar.gz"], ) # Now that we have the rules let's import from them to complete the work load("@build_bazel_rules_nodejs//:index.bzl", "check_rules_nodejs_version", "node_repositories", "yarn_install") # Assure we have at least a given rules_nodejs version -check_rules_nodejs_version(minimum_version_string = "3.6.0") +check_rules_nodejs_version(minimum_version_string = "3.7.0") # Setup the Node.js toolchain for the architectures we want to support # diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.exporters.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.exporters.md index 883dbcfe289cb..efba24c008264 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.exporters.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.exporters.md @@ -10,5 +10,7 @@ exporters: { datatableToCSV: typeof datatableToCSV; CSV_MIME_TYPE: string; + cellHasFormulas: (val: string) => boolean; + tableHasFormulas: (columns: import("../../expressions").DatatableColumn[], rows: Record[]) => boolean; } ``` diff --git a/docs/management/images/management-saved-objects.png b/docs/management/images/management-saved-objects.png index ba1f5af581dfd..0ee720cfdb39d 100644 Binary files a/docs/management/images/management-saved-objects.png and b/docs/management/images/management-saved-objects.png differ diff --git a/docs/management/managing-saved-objects.asciidoc b/docs/management/managing-saved-objects.asciidoc index 14d2ca63dd143..5b39c6ad1c4cd 100644 --- a/docs/management/managing-saved-objects.asciidoc +++ b/docs/management/managing-saved-objects.asciidoc @@ -37,12 +37,15 @@ and select *Relationships*. [[managing-saved-objects-export-objects]] === Import and export -Using the import and export commands, you can move objects between different +Using the import and export actions, you can move objects between different {kib} instances. This action is useful when you have multiple environments for development and production. Import and export also work well when you have a large number of objects to update and want to batch the process. +In addition to the user interface, {kib} provides beta <> and <> APIs if +you want to automate this process. + [float] ==== Compatibility across versions diff --git a/docs/spaces/images/change-space.png b/docs/spaces/images/change-space.png index fcf379afec84c..7c55ed0c2d6a5 100644 Binary files a/docs/spaces/images/change-space.png and b/docs/spaces/images/change-space.png differ diff --git a/docs/spaces/images/edit-space-feature-visibility.png b/docs/spaces/images/edit-space-feature-visibility.png index 3a74c21fe2635..0132337f4a7c6 100644 Binary files a/docs/spaces/images/edit-space-feature-visibility.png and b/docs/spaces/images/edit-space-feature-visibility.png differ diff --git a/docs/spaces/images/edit-space.png b/docs/spaces/images/edit-space.png index c4565a3ba0f4a..c78e0d14b0d4c 100644 Binary files a/docs/spaces/images/edit-space.png and b/docs/spaces/images/edit-space.png differ diff --git a/docs/spaces/images/securing-spaces.png b/docs/spaces/images/securing-spaces.png deleted file mode 100644 index e109e66b4cec6..0000000000000 Binary files a/docs/spaces/images/securing-spaces.png and /dev/null differ diff --git a/docs/spaces/images/space-management.png b/docs/spaces/images/space-management.png index 9d68be0d19f0d..2668758a98f4c 100644 Binary files a/docs/spaces/images/space-management.png and b/docs/spaces/images/space-management.png differ diff --git a/docs/spaces/images/space-selector.png b/docs/spaces/images/space-selector.png deleted file mode 100644 index b2576cbc9acc4..0000000000000 Binary files a/docs/spaces/images/space-selector.png and /dev/null differ diff --git a/docs/spaces/images/spaces-configure-landing-page.png b/docs/spaces/images/spaces-configure-landing-page.png index 15006594b6d7b..335a64dc1c743 100644 Binary files a/docs/spaces/images/spaces-configure-landing-page.png and b/docs/spaces/images/spaces-configure-landing-page.png differ diff --git a/docs/spaces/images/spaces-roles.png b/docs/spaces/images/spaces-roles.png index 407926895daa8..031b319cfad3e 100644 Binary files a/docs/spaces/images/spaces-roles.png and b/docs/spaces/images/spaces-roles.png differ diff --git a/docs/spaces/index.asciidoc b/docs/spaces/index.asciidoc index 9501043eb24b6..aeeb7b45ccd8a 100644 --- a/docs/spaces/index.asciidoc +++ b/docs/spaces/index.asciidoc @@ -12,7 +12,7 @@ spaces, you're asked to choose a space when you log in to Kibana. You can change current space at any time by using the menu. [role="screenshot"] -image::spaces/images/change-space.png["Change current space menu"] +image::images/change-space.png["Change current space menu"] Kibana supports spaces in several ways. You can: @@ -40,7 +40,7 @@ Open the main menu, then click *Stack Management > Spaces* for an overview of yo for you to create, edit, and delete spaces. [role="screenshot"] -image::spaces/images/space-management.png["Space management"] +image::images/space-management.png["Space management"] [float] ==== Create or edit a space @@ -57,7 +57,7 @@ You cannot change the space identifier once you create the space. if you prefer to create spaces programatically. [role="screenshot"] -image::spaces/images/edit-space.png["Space management"] +image::images/edit-space.png["Space management"] [float] ==== Delete a space @@ -81,7 +81,7 @@ to specific features on a per-user basis, you must configure <>. [role="screenshot"] -image::spaces/images/edit-space-feature-visibility.png["Controlling features visiblity"] +image::images/edit-space-feature-visibility.png["Controlling features visiblity"] [float] [[spaces-control-user-access]] @@ -95,26 +95,13 @@ while analysts or executives might have Dashboard and Canvas with read-only priv See <> for details. [role="screenshot"] -image::spaces/images/spaces-roles.png["Controlling features visiblity"] +image::images/spaces-roles.png["Controlling features visiblity"] [float] [[spaces-moving-objects]] === Move saved objects between spaces -To <> from one space to another, open the main menu, -then click *Stack Management > Saved Objects*. - -Alternately, you can move objects using {kib}'s <> -interface. - -. Navigate to the space that contains your saved objects. -. Export your saved objects. -. Navigate to the space where you want to import the objects. -. Import your saved objects. -. (Optional) Delete objects in the export space that you no longer need. - -{kib} also has beta <> and -<> APIs if you want to automate this process. +To move saved objects between spaces, you can <>, or <>. [float] [[spaces-default-route]] @@ -125,10 +112,10 @@ The landing page can route users to a specific dashboard, application, or saved To configure the landing page, use the default route setting in < {kib} > Advanced settings>>. -For example, you might set the default route to `/app/kibana#/dashboards`. +For example, you might set the default route to `/app/dashboards`. [role="screenshot"] -image::spaces/images/spaces-configure-landing-page.png["Configure space-level landing page"] +image::images/spaces-configure-landing-page.png["Configure space-level landing page"] [float] diff --git a/docs/user/dashboard/lens.asciidoc b/docs/user/dashboard/lens.asciidoc index 2071f17ecff3d..7d0e684e5f81b 100644 --- a/docs/user/dashboard/lens.asciidoc +++ b/docs/user/dashboard/lens.asciidoc @@ -316,10 +316,16 @@ Each *Layer* in a visualization is associated with an index pattern and mutiple You can also change the index pattern for a single *Layer*. [float] -[[why-my-field-x-is-missing-from-the-fields-list]] -===== Why is my field X missing from the fields list? +[[why-my-field-is-missing-from-the-fields-list]] +===== Why is my field missing from the fields list? -*Lens* does not support the visualization of full-text fields, therefore it is not showing them in the data summary. +Fields do not appear in the *Available fields* in the following scenarios: +* The field is a full-text field. +* The field is a `geo_point` field +* The field is a `flattened` field. +* The field is a `object` field. + +Verify if the field appears in the *Empty fields* list. *Lens* uses heuristics to determine if the fields contain values. For sparse data sets, the heuristics are less precise. [float] [[how-to-handle-gaps-in-time-series-visualizations]] @@ -370,3 +376,9 @@ Here's a short list of few different aspects to check: ** If a custom `Number` configuration is used, check that the color stop values are covering the current data range. ** If a `Percent` configuration is used, and the data range changes, the colors displayed are affected. + +[float] +[[is-it-possible-to-show-icons-in-datatable]] +===== Is it possible to display icons in data tables? + +You can display icons with <> in data tables. diff --git a/docs/user/images/features-control.png b/docs/user/images/features-control.png deleted file mode 100755 index abe75d5ab6fc1..0000000000000 Binary files a/docs/user/images/features-control.png and /dev/null differ diff --git a/docs/user/images/select-your-space.png b/docs/user/images/select-your-space.png old mode 100755 new mode 100644 index 887e8eea27c5c..2580455162fec Binary files a/docs/user/images/select-your-space.png and b/docs/user/images/select-your-space.png differ diff --git a/docs/user/introduction.asciidoc b/docs/user/introduction.asciidoc index 82ca11f2162fd..783fa2b1c521f 100644 --- a/docs/user/introduction.asciidoc +++ b/docs/user/introduction.asciidoc @@ -206,7 +206,7 @@ image::images/rules-and-connectors.png[Rules and Connectors view] === Organize your work in spaces Want to share {kib}’s goodness with other people or teams without overwhelming them? You can do so -with <>, built for organizing your visualizations, dashboards, and indices. +with <>, built for organizing your visualizations, dashboards, and index patterns. Think of a space as its own mini {kib} installation—it’s isolated from all other spaces, so you can tailor it to your specific needs without impacting others. @@ -234,15 +234,15 @@ For example, roles with no access to an app will not have access to its alerts. ==== Control feature visibility You can take spaces one step further and control which features are visible -within each space. For example, you might hide **Dev Tools** in your "Executive" -space or show **Stack Monitoring** only in your "Admin" space. +within each space. For example, you might hide **Dev Tools** in your "Marketing" +space or show **Stack Monitoring** only in your "Engineering" space. Controlling feature visibility is not a security feature. To secure access to specific features on a per-user basis, you must configure <>. [role="screenshot"] -image::images/features-control.png[Features Controls view] +image::spaces/images/edit-space-feature-visibility.png[Features Controls view] [float] [[intro-kibana-Security]] @@ -260,7 +260,7 @@ see <>. allowing you to login using {es}’s built-in realms, or by your own single sign-on provider. [role="screenshot"] -image::images/login-screen.png[Login page] +image::security/images/kibana-login.png[Login page] [float] ==== Secure access @@ -281,7 +281,7 @@ while analysts or executives might have *Dashboard* and *Canvas* with read-only levels, or you can automate role creation via our <>. [role="screenshot"] -image::images/roles-and-privileges.png[{kib privileges}] +image::spaces/images/spaces-roles.png[{kib privileges}] [float] ==== Audit access diff --git a/docs/user/security/access-agreement.asciidoc b/docs/user/security/access-agreement.asciidoc index 362eb80501210..9d9a0bb61a90b 100644 --- a/docs/user/security/access-agreement.asciidoc +++ b/docs/user/security/access-agreement.asciidoc @@ -2,14 +2,16 @@ [[xpack-security-access-agreement]] === Access agreement -Some work environments require you to acknowledge and accept an agreement before you can access {kib}, which can contain sensitive information. The agreement text supports Markdown format and can be specified using the `xpack.security.authc.providers...accessAgreement.message` setting. +Access agreement is a https://www.elastic.co/subscriptions[subscription feature] that requires users to acknowledge and accept an +agreement before accessing {kib}. The agreement text supports Markdown format and can be specified using the +`xpack.security.authc.providers...accessAgreement.message` setting. [NOTE] ============================================================================ You need to acknowledge the access agreement only once per session, and {kib} reports the acknowledgement in the audit logs. ============================================================================ -Here is how your `kibana.yml` can look like if you define an access agreement: +Here is an example of defining an access agreement in `kibana.yml`: [source,yaml] -------------------------------------------------------------------------------- @@ -17,11 +19,14 @@ xpack.security.authc.providers: basic.basic1: order: 0 accessAgreement: - message: "**You are accessing a system with a sensitive information** \n\n - By logging in, you acknowledge that (shortened ...)" + message: | + **You are accessing a system with sensitive information** + + By logging in, you acknowledge that information system usage + ...(shortened) -------------------------------------------------------------------------------- When you authenticate using `basic.basic1`, you'll see the following agreement that you must acknowledge before you can access {kib}: [role="screenshot"] -image::user/security/images/access-agreement.png["Access Agreement UI"] +image::images/access-agreement.png["Access Agreement UI"] diff --git a/docs/user/security/api-keys/images/api-keys.png b/docs/user/security/api-keys/images/api-keys.png index ec4111a443253..2a9df066fc3b8 100644 Binary files a/docs/user/security/api-keys/images/api-keys.png and b/docs/user/security/api-keys/images/api-keys.png differ diff --git a/docs/user/security/api-keys/images/create-api-key.png b/docs/user/security/api-keys/images/create-api-key.png index b0041f69b05b6..f80bd10db43d4 100644 Binary files a/docs/user/security/api-keys/images/create-api-key.png and b/docs/user/security/api-keys/images/create-api-key.png differ diff --git a/docs/user/security/api-keys/index.asciidoc b/docs/user/security/api-keys/index.asciidoc index 6b92ab3c6656a..94301568b6438 100644 --- a/docs/user/security/api-keys/index.asciidoc +++ b/docs/user/security/api-keys/index.asciidoc @@ -17,7 +17,7 @@ remote sources, without a live user interaction. To manage API keys, open the main menu, then click *Stack Management > API Keys*. [role="screenshot"] -image:user/security/api-keys/images/api-keys.png["API Keys UI"] +image:images/api-keys.png["API Keys UI"] [float] [[api-keys-service]] @@ -49,7 +49,7 @@ cluster privileges to use API keys in {kib}. To manage roles, open the main menu To create an API key, open the main menu, then click *Stack Management > API Keys > Create API key*. [role="screenshot"] -image:user/security/api-keys/images/create-api-key.png["Create API Key UI"] +image:images/create-api-key.png["Create API Key UI"] Once created, you can copy the API key (Base64 encoded) and use it to send requests to {es} on your behalf. For example: diff --git a/docs/user/security/audit-logging.asciidoc b/docs/user/security/audit-logging.asciidoc index 5808e56d6d289..db40feab20ce9 100644 --- a/docs/user/security/audit-logging.asciidoc +++ b/docs/user/security/audit-logging.asciidoc @@ -2,9 +2,9 @@ [[xpack-security-audit-logging]] === Audit logs -You can enable auditing to keep track of security-related events such as -authorization success and failures. Logging these events enables you to monitor -{kib} for suspicious activity and provides evidence in the event of an attack. +Audit logging is a https://www.elastic.co/subscriptions[subscription feature] that you can enable to keep track of security-related events, +such as authorization success and failures. Logging these events enables you to monitor {kib} for suspicious activity and provides evidence +in the event of an attack. Use the {kib} audit logs in conjunction with {ref}/enable-audit-logging.html[{es} audit logging] to get a holistic view of all security related events. {kib} defers to the {es} security diff --git a/docs/user/security/authentication/index.asciidoc b/docs/user/security/authentication/index.asciidoc index 5506e7ab375a2..bc564308c057e 100644 --- a/docs/user/security/authentication/index.asciidoc +++ b/docs/user/security/authentication/index.asciidoc @@ -61,7 +61,7 @@ xpack.security.authc.providers: -------------------------------------------------------------------------------- [role="screenshot"] -image::user/security/images/kibana-login.png["Login Selector UI"] +image::security/images/kibana-login.png["Login Selector UI"] For more information, refer to <>. @@ -82,7 +82,9 @@ For more information about basic authentication and built-in users, see [[token-authentication]] ==== Token authentication -Token authentication allows users to log in using the same {kib} provided login form as basic authentication, and is based on the Native security realm or LDAP security realm that is provided by {es}. The token authentication provider is built on {es} token APIs. +Token authentication is a https://www.elastic.co/subscriptions[subscription feature]. This allows users to log in using the same {kib} +provided login form as basic authentication, and is based on the Native security realm or LDAP security realm that is provided by {es}. The +token authentication provider is built on {es} token APIs. Prior to configuring {kib}, ensure token support is enabled in {es}. See the {ref}/security-api-get-token.html[{es} token API] documentation for more information. @@ -107,7 +109,11 @@ Switching to the token authentication provider from basic one will make {kib} to PKI authentication will not work if {kib} is hosted behind a TLS termination reverse proxy. In this configuration, {kib} does not have direct access to the client certificates and cannot authenticate the user. ============================================================================ -PKI authentication allows users to log into {kib} using X.509 client certificates that must be presented while connecting to {kib}. The certificates must first be accepted for authentication on the {kib} TLS layer, and then they are further validated by an {es} PKI realm. The PKI authentication provider relies on the {es} {ref}/security-api-delegate-pki-authentication.html[Delegate PKI authentication API] to exchange X.509 client certificates to access tokens. All subsequent requests to {es} APIs on behalf of users will be authenticated using these access tokens. +PKI authentication is a https://www.elastic.co/subscriptions[subscription feature]. This allows users to log +into {kib} using X.509 client certificates that must be presented while connecting to {kib}. The certificates must first be accepted for +authentication on the {kib} TLS layer, and then they are further validated by an {es} PKI realm. The PKI authentication provider relies on +the {es} {ref}/security-api-delegate-pki-authentication.html[Delegate PKI authentication API] to exchange X.509 client certificates to +access tokens. All subsequent requests to {es} APIs on behalf of users will be authenticated using these access tokens. Prior to configuring {kib}, ensure that the PKI realm is enabled in {es} and configured to permit delegation. See {ref}/configuring-pki-realm.html[Configuring a PKI realm] for more information. @@ -144,9 +150,11 @@ Note that with `server.ssl.clientAuthentication` set to `required`, users are as [[saml]] ==== SAML single sign-on -SAML authentication allows users to log in to {kib} with an external Identity Provider, such as Okta or Auth0. Make sure that SAML is enabled and configured in {es} before setting it up in {kib}. See {ref}/saml-guide.html[Configuring SAML single sign-on on the Elastic Stack]. +SAML authentication is part of single sign-on (SSO), a https://www.elastic.co/subscriptions[subscription feature]. This allows users to log +in to {kib} with an external Identity Provider, such as Okta or Auth0. Make sure that SAML is enabled and configured in {es} before setting +it up in {kib}. See {ref}/saml-guide.html[Configuring SAML single sign-on on the Elastic Stack]. -Enable the SAML authentication specifying which SAML realm in {es} should be used: +Enable SAML authentication by specifying which SAML realm in {es} should be used: [source,yaml] -------------------------------------------------------------------------------- @@ -156,7 +164,7 @@ xpack.security.authc.providers: realm: saml1 -------------------------------------------------------------------------------- -You can log in to {kib} via SAML Single Sign-On by navigating directly to the {kib} URL. If you aren't authenticated, you are redirected to the Identity Provider for login. Most Identity Providers maintain a long-lived session. If you log in to a different application using the same Identity Provider in the same browser, you are automatically authenticated. An exception is if {es} or the Identity Provider is configured to force you to re-authenticate. This login scenario is called _Service Provider initiated login_. +You can log in to {kib} via SAML SSO by navigating directly to the {kib} URL. If you aren't authenticated, you are redirected to the Identity Provider for login. Most Identity Providers maintain a long-lived session. If you log in to a different application using the same Identity Provider in the same browser, you are automatically authenticated. An exception is if {es} or the Identity Provider is configured to force you to re-authenticate. This login scenario is called _Service Provider initiated login_. It's also possible to configure multiple SAML authentication providers at the same time. In this case, you will need to choose which provider to use for login at the Login Selector UI: @@ -176,7 +184,7 @@ xpack.security.authc.providers: [float] ===== SAML and basic authentication -You can also configure both SAML and basic authentication for the same {kib} instance. This might be the case for {kib} or {es} admins whose accounts aren't linked to the Single Sign-On users database: +You can also configure both SAML and basic authentication for the same {kib} instance. This might be the case for {kib} or {es} admins whose accounts aren't linked to the SSO users database: [source,yaml] -------------------------------------------------------------------------------- @@ -196,10 +204,11 @@ To support basic authentication for the applications like `curl` or when the `Au [[oidc]] ==== OpenID Connect single sign-on -Similar to SAML, authentication with OpenID Connect allows users to log in to {kib} using an OpenID Connect Provider such as Google, or Okta. OpenID Connect -should also be configured in {es}. For more details, see {ref}/oidc-guide.html[Configuring single sign-on to the {stack} using OpenID Connect]. +OpenID Connect (OIDC) authentication is part of single sign-on (SSO), a https://www.elastic.co/subscriptions[subscription feature]. Similar +to SAML, authentication with OIDC allows users to log in to {kib} using an OIDC Provider such as Google, or Okta. OIDC should also +be configured in {es}. For more details, see {ref}/oidc-guide.html[Configuring single sign-on to the {stack} using OpenID Connect]. -Enable the OpenID Connect authentication specifying which OpenID Connect realm in {es} should be used: +Enable OIDC authentication by specifying which OIDC realm in {es} to use: [source,yaml] -------------------------------------------------------------------------------- @@ -209,7 +218,7 @@ xpack.security.authc.providers: realm: oidc1 -------------------------------------------------------------------------------- -If you want to use Third Party initiated Single Sign-On, configure your OpenID Provider to use `/api/security/oidc/initiate_login` as `Initiate Login URI`. +To use third party initiated SSO, configure your OpenID Provider to use `/api/security/oidc/initiate_login` as `Initiate Login URI`. It's also possible to configure multiple OpenID Connect authentication providers at the same time. In this case, you need to choose which provider to use for login at the Login Selector UI: @@ -229,7 +238,7 @@ xpack.security.authc.providers: [float] ===== OpenID Connect and basic authentication -You can also configure both OpenID Connect and basic authentication for the same {kib} instance. This might be the case for {kib} or {es} admins whose accounts aren't linked to the Single Sign-On users database: +You can also configure both OpenID Connect and basic authentication for the same {kib} instance. This might be the case for {kib} or {es} admins whose accounts aren't linked to the SSO users database: [source,yaml] -------------------------------------------------------------------------------- @@ -254,7 +263,7 @@ The following sections apply both to <> and <> [float] ===== Access and refresh tokens -Once the user logs in to {kib} Single Sign-On, either using SAML or OpenID Connect, {es} issues access and refresh tokens +Once the user logs in to {kib} with SSO, either using SAML or OpenID Connect, {es} issues access and refresh tokens that {kib} encrypts and stores as a part of its own session. This way, the user isn't redirected to the Identity Provider for every request that requires authentication. It also means that the {kib} session depends on the <> settings, and the user is automatically logged @@ -281,7 +290,8 @@ all applications associated with the active provider session. [[kerberos]] ==== Kerberos single sign-on -As with the previous SSOs, make sure that you have configured {es} first accordingly. See {ref}/kerberos-realm.html[Kerberos authentication]. +Kerberos authentication is part of single sign-on (SSO), a https://www.elastic.co/subscriptions[subscription feature]. Make sure that +Kerberos is enabled and configured in {es} before setting it up in {kib}. See {ref}/kerberos-realm.html[Kerberos authentication]. Next, to enable Kerberos in {kib}, you will need to enable the Kerberos authentication provider in the `kibana.yml` configuration file, as follows: @@ -455,7 +465,7 @@ xpack.security.sameSiteCookies: "None" For more information about possible values and implications, refer to <>. For more information about iframe and cookies, refer to https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe[iframe] and https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite[SameSite cookies]. -If you're embedding {kib} in a website that supports Single Sign-On with SAML, OpenID Connect, Kerberos, or PKI, it's highly advisable to configure {kib} as a part of the Single Sign-On setup. Operating in a single and properly configured security domain provides you with the most secure and seamless user experience. +If you're embedding {kib} in a website that supports single sign-on (SSO) with SAML, OpenID Connect, Kerberos, or PKI, it's highly advisable to configure {kib} as a part of the SSO setup. Operating in a single and properly configured security domain provides you with the most secure and seamless user experience. If you have multiple authentication providers enabled, and you want to automatically log in anonymous users when embedding anything other than dashboards and visualizations, then you will need to add the `auth_provider_hint=` query string parameter to the {kib} URL that you're embedding. diff --git a/docs/user/security/authorization/index.asciidoc b/docs/user/security/authorization/index.asciidoc index 523a90bdf07ce..df4ad4e2b89b0 100644 --- a/docs/user/security/authorization/index.asciidoc +++ b/docs/user/security/authorization/index.asciidoc @@ -63,11 +63,13 @@ With field-level security (FLS), you can instruct {es} to grant or deny access t .. `read` and `view_index_metadata` in the **Privileges** field. [role="screenshot"] -image::user/security/images/create-role-index-example.png[Create role with index privileges] +image::security/images/create-role-index-example.png[Create role with index privileges] [[index_privilege_dls_example]] ===== Example: Grant read access to specific documents in indices that match the `filebeat-*` pattern +{ref}/document-level-security.html[Document-level security] is a https://www.elastic.co/subscriptions[subscription feature]. + . Go to **Stack Management > Roles**, and then click **Create role**. . In **Index privileges**, enter: .. `filebeat-*` in the **Indices** field. @@ -87,7 +89,7 @@ image::user/security/images/create-role-index-example.png[Create role with index NOTE: {kib} automatically surrounds your DLS query with a `query` block, so you don't have to provide your own. [role="screenshot"] -image::user/security/images/create-role-dls-example.png[Create role with DLS index privileges] +image::security/images/create-role-dls-example.png[Create role with DLS index privileges] [[adding_kibana_privileges]] ==== {kib} privileges @@ -95,9 +97,9 @@ image::user/security/images/create-role-dls-example.png[Create role with DLS ind To assign {kib} privileges to the role, click **Add {kib} privilege** in the {kib} section. [role="screenshot"] -image::user/security/images/add-space-privileges.png[Add {kib} privileges] +image::spaces/images/spaces-roles.png[Add {kib} privileges] -Open the **Spaces** selection control to specify whether to grant the role access to all spaces *** Global (all spaces)** or one or more individual spaces. If you select *** Global (all spaces)**, you can’t select individual spaces until you clear your selection. +Open the **Spaces** selection control to specify whether to grant the role access to all spaces **All Spaces** or one or more individual spaces. If you select **All Spaces**, you can’t select individual spaces until you clear your selection. Use the **Privilege** menu to grant access to features. The default is **Custom**, which you can use to grant access to individual features. Otherwise, you can grant read and write access to all current and future features by selecting **All**, or grant read access to all current and future features by selecting **Read**. @@ -111,7 +113,7 @@ To apply your changes, click **Add {kib} privilege**. The privilege shows up und [role="screenshot"] -image::user/security/images/create-space-privilege.png[Add {kib} privilege] +image::security/images/create-space-privilege.png[Add {kib} privilege] ==== Feature availability @@ -139,9 +141,9 @@ Features are available to users when their roles grant access to the features, * ==== Assigning different privileges to different spaces -Using the same role, it’s possible to assign different privileges to different spaces. After you’ve added privileges, click **Add {kib} privilege**. If you’ve already added privileges for either *** Global (all spaces)** or an individual space, you will not be able to select these in the **Spaces** selection control. +Using the same role, it’s possible to assign different privileges to different spaces. After you’ve added privileges, click **Add {kib} privilege**. If you’ve already added privileges for either **All Spaces** or an individual space, you will not be able to select these in the **Spaces** selection control. -Additionally, if you’ve already assigned privileges at *** Global (all spaces)**, you are only able to assign additional privileges to individual spaces. Similar to the behavior of multiple roles granting the union of all privileges, {kib} privileges are also a union. If you’ve already granted the user the **All** privilege at *** Global (all spaces)**, you’re not able to restrict the role to only the **Read** privilege at an individual space. +Additionally, if you’ve already assigned privileges at **All Spaces**, you are only able to assign additional privileges to individual spaces. Similar to the behavior of multiple roles granting the union of all privileges, {kib} privileges are also a union. If you’ve already granted the user the **All** privilege at **All Spaces**, you’re not able to restrict the role to only the **Read** privilege at an individual space. ==== Privilege summary @@ -149,7 +151,7 @@ Additionally, if you’ve already assigned privileges at *** Global (all spaces) To view a summary of the privileges granted, click **View privilege summary**. [role="screenshot"] -image::user/security/images/view-privilege-summary.png[View privilege summary] +image::security/images/view-privilege-summary.png[View privilege summary] ==== Example 1: Grant all access to Dashboard at an individual space @@ -160,7 +162,7 @@ image::user/security/images/view-privilege-summary.png[View privilege summary] . Click **Add {kib} privilege**. [role="screenshot"] -image::user/security/images/privilege-example-1.png[Privilege example 1] +image::security/images/privilege-example-1.png[Privilege example 1] ==== Example 2: Grant all access to one space and read access to another @@ -173,12 +175,12 @@ image::user/security/images/privilege-example-1.png[Privilege example 1] . Click **Add {kib} privilege**. [role="screenshot"] -image::user/security/images/privilege-example-2.png[Privilege example 2] +image::security/images/privilege-example-2.png[Privilege example 2] ==== Example 3: Grant read access to all spaces and write access to an individual space . Click **Add {kib} privilege**. -. For **Spaces**, select *** Global (all spaces)**. +. For **Spaces**, select **All Spaces**. . For **Privilege**, select **Read**. . Click **Add {kib} privilege**. . For **Spaces**, select the individual space. @@ -186,4 +188,4 @@ image::user/security/images/privilege-example-2.png[Privilege example 2] . Click **Add {kib} privilege**. [role="screenshot"] -image::user/security/images/privilege-example-3.png[Privilege example 3] +image::security/images/privilege-example-3.png[Privilege example 3] diff --git a/docs/user/security/authorization/kibana-privileges.asciidoc b/docs/user/security/authorization/kibana-privileges.asciidoc index bbc8ec226fa7c..581210bb9d393 100644 --- a/docs/user/security/authorization/kibana-privileges.asciidoc +++ b/docs/user/security/authorization/kibana-privileges.asciidoc @@ -14,7 +14,7 @@ Assigning a base privilege grants access to all {kib} features, such as *Discove From the role management screen: [role="screenshot"] -image::user/security/images/assign_base_privilege.png[Assign base privilege] +image::security/images/assign-base-privilege.png[Assign base privilege] From the <>: [source,js] @@ -45,13 +45,13 @@ Assigning a feature privilege grants access to a specific feature. ===== Sub-feature privileges Some features allow for finer access control than the `all` and `read` privileges. -This additional level of control is available in the Gold subscription level and higher. +This additional level of control is a https://www.elastic.co/subscriptions[subscription feature]. ===== Assigning feature privileges From the role management screen: [role="screenshot"] -image::user/security/images/assign_feature_privilege.png[Assign feature privilege] +image::security/images/assign-subfeature-privilege.png[Assign feature privilege] From the <>: [source,js] diff --git a/docs/user/security/encryption-keys/index.asciidoc b/docs/user/security/encryption-keys/index.asciidoc index 58c0c0bb775ca..ff35070c2c961 100644 --- a/docs/user/security/encryption-keys/index.asciidoc +++ b/docs/user/security/encryption-keys/index.asciidoc @@ -1,5 +1,5 @@ [[kibana-encryption-keys]] -=== Set up encryptions keys to protect sensitive information +=== Set up encryption keys to protect sensitive information The `kibana-encryption-keys` command helps you set up encryption keys that {kib} uses to protect sensitive information. @@ -18,7 +18,7 @@ bin/kibana-encryption-keys generate === Description {kib} uses encryption keys in several areas, ranging from encrypting data -in {kib} associated indices to storing session information. By defining these +in {kib} associated indices to storing session information. By defining these encryption keys in your configuration, you'll ensure consistent operations across restarts. diff --git a/docs/user/security/images/access-agreement.png b/docs/user/security/images/access-agreement.png index ecb6122875cb8..b7b762a88e85c 100644 Binary files a/docs/user/security/images/access-agreement.png and b/docs/user/security/images/access-agreement.png differ diff --git a/docs/user/security/images/add-space-privileges.png b/docs/user/security/images/add-space-privileges.png deleted file mode 100644 index d2fcbe76c1a06..0000000000000 Binary files a/docs/user/security/images/add-space-privileges.png and /dev/null differ diff --git a/docs/user/security/images/assign-base-privilege.png b/docs/user/security/images/assign-base-privilege.png new file mode 100644 index 0000000000000..17be4b9ef2bf1 Binary files /dev/null and b/docs/user/security/images/assign-base-privilege.png differ diff --git a/docs/user/security/images/assign-subfeature-privilege.png b/docs/user/security/images/assign-subfeature-privilege.png new file mode 100644 index 0000000000000..c83cd6b165157 Binary files /dev/null and b/docs/user/security/images/assign-subfeature-privilege.png differ diff --git a/docs/user/security/images/assign_base_privilege.png b/docs/user/security/images/assign_base_privilege.png deleted file mode 100644 index 93bed0de05555..0000000000000 Binary files a/docs/user/security/images/assign_base_privilege.png and /dev/null differ diff --git a/docs/user/security/images/assign_feature_privilege.png b/docs/user/security/images/assign_feature_privilege.png deleted file mode 100644 index d42ec208325a3..0000000000000 Binary files a/docs/user/security/images/assign_feature_privilege.png and /dev/null differ diff --git a/docs/user/security/images/create-role-dls-example.png b/docs/user/security/images/create-role-dls-example.png index b0893502448b8..02b91ccf8820e 100644 Binary files a/docs/user/security/images/create-role-dls-example.png and b/docs/user/security/images/create-role-dls-example.png differ diff --git a/docs/user/security/images/create-role-index-example.png b/docs/user/security/images/create-role-index-example.png index 200d01e0d56c5..8f95a74194274 100644 Binary files a/docs/user/security/images/create-role-index-example.png and b/docs/user/security/images/create-role-index-example.png differ diff --git a/docs/user/security/images/create-space-privilege.png b/docs/user/security/images/create-space-privilege.png old mode 100755 new mode 100644 index 2e6cc299bfc54..093a339122084 Binary files a/docs/user/security/images/create-space-privilege.png and b/docs/user/security/images/create-space-privilege.png differ diff --git a/docs/user/security/images/kibana-login.png b/docs/user/security/images/kibana-login.png index 813f2c703908d..cd9df9f563879 100644 Binary files a/docs/user/security/images/kibana-login.png and b/docs/user/security/images/kibana-login.png differ diff --git a/docs/user/security/images/mutual-tls-role-mapping.png b/docs/user/security/images/mutual-tls-role-mapping.png index e870efe5d5b74..42ba56a2cac75 100644 Binary files a/docs/user/security/images/mutual-tls-role-mapping.png and b/docs/user/security/images/mutual-tls-role-mapping.png differ diff --git a/docs/user/security/images/privilege-example-1.png b/docs/user/security/images/privilege-example-1.png index b8fb4d15b8f77..59e71e3cb3b24 100644 Binary files a/docs/user/security/images/privilege-example-1.png and b/docs/user/security/images/privilege-example-1.png differ diff --git a/docs/user/security/images/privilege-example-2.png b/docs/user/security/images/privilege-example-2.png old mode 100755 new mode 100644 index 2530ca5da36e1..36b26b131a3a2 Binary files a/docs/user/security/images/privilege-example-2.png and b/docs/user/security/images/privilege-example-2.png differ diff --git a/docs/user/security/images/privilege-example-3.png b/docs/user/security/images/privilege-example-3.png old mode 100755 new mode 100644 index c2e5db3a18e20..a0004905023f0 Binary files a/docs/user/security/images/privilege-example-3.png and b/docs/user/security/images/privilege-example-3.png differ diff --git a/docs/user/security/images/tutorial-secure-access-example-1-role.png b/docs/user/security/images/tutorial-secure-access-example-1-role.png index 53540da7170ea..a27b56315e61c 100644 Binary files a/docs/user/security/images/tutorial-secure-access-example-1-role.png and b/docs/user/security/images/tutorial-secure-access-example-1-role.png differ diff --git a/docs/user/security/images/tutorial-secure-access-example-1-test.png b/docs/user/security/images/tutorial-secure-access-example-1-test.png index 305b97017a9d8..2ff4fb4b09c91 100644 Binary files a/docs/user/security/images/tutorial-secure-access-example-1-test.png and b/docs/user/security/images/tutorial-secure-access-example-1-test.png differ diff --git a/docs/user/security/images/view-privilege-summary.png b/docs/user/security/images/view-privilege-summary.png index 7d2f3018d7de9..9e0e0fcc4f80b 100644 Binary files a/docs/user/security/images/view-privilege-summary.png and b/docs/user/security/images/view-privilege-summary.png differ diff --git a/docs/user/security/role-mappings/images/role-mappings-create-step-1.png b/docs/user/security/role-mappings/images/role-mappings-create-step-1.png index 76aee8fd85b66..06ee1f3bc405d 100644 Binary files a/docs/user/security/role-mappings/images/role-mappings-create-step-1.png and b/docs/user/security/role-mappings/images/role-mappings-create-step-1.png differ diff --git a/docs/user/security/role-mappings/images/role-mappings-create-step-2.gif b/docs/user/security/role-mappings/images/role-mappings-create-step-2.gif index c4a982d96c365..766158a96bf1f 100644 Binary files a/docs/user/security/role-mappings/images/role-mappings-create-step-2.gif and b/docs/user/security/role-mappings/images/role-mappings-create-step-2.gif differ diff --git a/docs/user/security/role-mappings/images/role-mappings-grid.png b/docs/user/security/role-mappings/images/role-mappings-grid.png index f33cd7a3652b2..8044096e15489 100644 Binary files a/docs/user/security/role-mappings/images/role-mappings-grid.png and b/docs/user/security/role-mappings/images/role-mappings-grid.png differ diff --git a/docs/user/security/role-mappings/index.asciidoc b/docs/user/security/role-mappings/index.asciidoc index ca3ca9a686892..df4ded4321c13 100644 --- a/docs/user/security/role-mappings/index.asciidoc +++ b/docs/user/security/role-mappings/index.asciidoc @@ -2,11 +2,10 @@ [[role-mappings]] === Role mappings -Role mappings allow you to describe which roles to assign to your users -using a set of rules. Role mappings are required when authenticating via -an external identity provider, such as Active Directory, Kerberos, PKI, OIDC, -or SAML. +Role mappings are part of single sign-on (SSO), a https://www.elastic.co/subscriptions[subscription feature]. This feature allows you to +describe which roles to assign to your users using a set of rules. +Role mappings are required when authenticating via an external identity provider, such as Active Directory, Kerberos, PKI, OIDC, or SAML. Role mappings have no effect for users inside the `native` or `file` realms. To manage your role mappings, open the main menu, then click *Stack Management > Role Mappings*. @@ -17,7 +16,7 @@ With *Role mappings*, you can: * Create/Edit/Delete role mappings [role="screenshot"] -image:user/security/role-mappings/images/role-mappings-grid.png["Role mappings"] +image:images/role-mappings-grid.png["Role mappings"] [float] ==== Required permissions @@ -46,12 +45,12 @@ starts with `sls_`, *or* belongs to the `executive` group. First, we give the role mapping a name, and assign the `sales` role: [role="screenshot"] -image:user/security/role-mappings/images/role-mappings-create-step-1.png["Create role mapping, step 1"] +image:images/role-mappings-create-step-1.png["Create role mapping, step 1"] Next, we define the two rules, making sure to set the group to *Any are true*: [role="screenshot"] -image:user/security/role-mappings/images/role-mappings-create-step-2.gif["Create role mapping, step 2"] +image:images/role-mappings-create-step-2.gif["Create role mapping, step 2"] Click *Save role mapping* once you're finished. diff --git a/docs/user/security/securing-communications/elasticsearch-mutual-tls.asciidoc b/docs/user/security/securing-communications/elasticsearch-mutual-tls.asciidoc index 63fd2799c90cf..57ecb1705e007 100644 --- a/docs/user/security/securing-communications/elasticsearch-mutual-tls.asciidoc +++ b/docs/user/security/securing-communications/elasticsearch-mutual-tls.asciidoc @@ -109,7 +109,7 @@ This role mapping will assign the `kibana_system` role to any user that matches certificate's DN attribute: [role="screenshot"] -image:user/security/images/mutual-tls-role-mapping.png["Role mapping for the {kib} client certificate"] +image:security/images/mutual-tls-role-mapping.png["Role mapping for the {kib} client certificate"] For more information, see <>. -- diff --git a/docs/user/security/tutorials/how-to-secure-access-to-kibana.asciidoc b/docs/user/security/tutorials/how-to-secure-access-to-kibana.asciidoc index 199f138347fa0..f5b799d444102 100644 --- a/docs/user/security/tutorials/how-to-secure-access-to-kibana.asciidoc +++ b/docs/user/security/tutorials/how-to-secure-access-to-kibana.asciidoc @@ -61,7 +61,7 @@ Create a Marketing space for your marketing analysts to use. If you’ve followed the example above, you should end up with a space that looks like this: + [role="screenshot"] -image::user/security/images/tutorial-secure-access-example-1-space.png[Create space UI] +image::security/images/tutorial-secure-access-example-1-space.png[Create space UI] [float] @@ -93,7 +93,7 @@ TIP: You can add multiple patterns of indices, and grant different access levels If you’ve followed the example above, you should end up with a role that looks like this: + [role="screenshot"] -image::user/security/images/tutorial-secure-access-example-1-role.png[Create role UI] +image::security/images/tutorial-secure-access-example-1-role.png[Create role UI] [float] @@ -108,7 +108,7 @@ Now that you created a role, create a user account. . Click *Create user*. [role="screenshot"] -image::user/security/images/tutorial-secure-access-example-1-user.png[Create user UI] +image::security/images/tutorial-secure-access-example-1-user.png[Create user UI] [float] ==== Verify @@ -121,7 +121,7 @@ Verify that the user and role are working correctly. You’re taken into the `Marketing` space, and the main navigation shows only the *Dashboard* application. + [role="screenshot"] -image::user/security/images/tutorial-secure-access-example-1-test.png[Verifying access to dashboards] +image::security/images/tutorial-secure-access-example-1-test.png[Verifying access to dashboards] [float] diff --git a/package.json b/package.json index 2ee46c031fbf0..0875242a18da9 100644 --- a/package.json +++ b/package.json @@ -449,7 +449,7 @@ "@babel/traverse": "^7.12.12", "@babel/types": "^7.12.12", "@bazel/ibazel": "^0.15.10", - "@bazel/typescript": "^3.6.0", + "@bazel/typescript": "^3.7.0", "@cypress/snapshot": "^2.1.7", "@cypress/webpack-preprocessor": "^5.6.0", "@elastic/eslint-config-kibana": "link:bazel-bin/packages/elastic-eslint-config-kibana", diff --git a/src/plugins/dashboard/public/application/actions/export_csv_action.test.tsx b/src/plugins/dashboard/public/application/actions/export_csv_action.test.tsx index 20144b47e474b..2d12d6e797528 100644 --- a/src/plugins/dashboard/public/application/actions/export_csv_action.test.tsx +++ b/src/plugins/dashboard/public/application/actions/export_csv_action.test.tsx @@ -105,7 +105,7 @@ describe('Export CSV action', () => { | Record; expect(result).toEqual({ 'Hello Kibana.csv': { - content: `First Name,Last Name${LINE_FEED_CHARACTER}Kibana,undefined${LINE_FEED_CHARACTER}`, + content: `First Name,Last Name${LINE_FEED_CHARACTER}Kibana,${LINE_FEED_CHARACTER}`, type: 'text/plain;charset=utf-8', }, }); diff --git a/src/plugins/dashboard/public/application/actions/export_csv_action.tsx b/src/plugins/dashboard/public/application/actions/export_csv_action.tsx index c2f651360da1b..dd6eeb92ef932 100644 --- a/src/plugins/dashboard/public/application/actions/export_csv_action.tsx +++ b/src/plugins/dashboard/public/application/actions/export_csv_action.tsx @@ -94,6 +94,7 @@ export class ExportCSVAction implements Action { csvSeparator: this.params.core.uiSettings.get('csv:separator', ','), quoteValues: this.params.core.uiSettings.get('csv:quoteValues', true), formatFactory, + escapeFormulaValues: false, }), type: exporters.CSV_MIME_TYPE, }; diff --git a/src/plugins/data/common/exports/constants.ts b/src/plugins/data/common/exports/constants.ts new file mode 100644 index 0000000000000..9c256d4d3ea97 --- /dev/null +++ b/src/plugins/data/common/exports/constants.ts @@ -0,0 +1,11 @@ +/* + * 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. + */ + +export const CSV_FORMULA_CHARS = ['=', '+', '-', '@']; +export const nonAlphaNumRE = /[^a-zA-Z0-9]/; +export const allDoubleQuoteRE = /"/g; diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/escape_value.test.ts b/src/plugins/data/common/exports/escape_value.test.ts similarity index 93% rename from x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/escape_value.test.ts rename to src/plugins/data/common/exports/escape_value.test.ts index 6bc1a3b4627a6..9463af644d417 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/escape_value.test.ts +++ b/src/plugins/data/common/exports/escape_value.test.ts @@ -1,8 +1,9 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 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 expect from '@kbn/expect'; diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/escape_value.ts b/src/plugins/data/common/exports/escape_value.ts similarity index 65% rename from x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/escape_value.ts rename to src/plugins/data/common/exports/escape_value.ts index e4dbdb2f396a4..9277f792a4b86 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/escape_value.ts +++ b/src/plugins/data/common/exports/escape_value.ts @@ -1,15 +1,14 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 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 { allDoubleQuoteRE, nonAlphaNumRE } from './constants'; +import { cellHasFormulas } from './formula_checks'; -import { RawValue } from '../types'; -import { cellHasFormulas } from './cell_has_formula'; - -const nonAlphaNumRE = /[^a-zA-Z0-9]/; -const allDoubleQuoteRE = /"/g; +type RawValue = string | object | null | undefined; export function createEscapeValue( quoteValues: boolean, @@ -22,7 +21,6 @@ export function createEscapeValue( return `"${formulasEscaped.replace(allDoubleQuoteRE, '""')}"`; } } - return val == null ? '' : val.toString(); }; } diff --git a/src/plugins/data/common/exports/export_csv.test.ts b/src/plugins/data/common/exports/export_csv.test.ts index 2070ec9417cd1..8bf44fe48a589 100644 --- a/src/plugins/data/common/exports/export_csv.test.ts +++ b/src/plugins/data/common/exports/export_csv.test.ts @@ -17,6 +17,7 @@ function getDefaultOptions() { csvSeparator: ',', quoteValues: true, formatFactory, + escapeFormulaValues: false, }; } @@ -71,4 +72,16 @@ describe('CSV exporter', () => { 'columnOne\r\n"Formatted_""value"""\r\n' ); }); + + test('should escape formulas', () => { + const datatable = getDataTable(); + datatable.rows[0].col1 = '=1'; + expect( + datatableToCSV(datatable, { + ...getDefaultOptions(), + escapeFormulaValues: true, + formatFactory: () => ({ convert: (v: unknown) => v } as FieldFormat), + }) + ).toMatch('columnOne\r\n"\'=1"\r\n'); + }); }); diff --git a/src/plugins/data/common/exports/export_csv.tsx b/src/plugins/data/common/exports/export_csv.tsx index f52e227c667cc..d4477e72b64c4 100644 --- a/src/plugins/data/common/exports/export_csv.tsx +++ b/src/plugins/data/common/exports/export_csv.tsx @@ -10,40 +10,26 @@ import { FormatFactory } from 'src/plugins/data/common/field_formats/utils'; import { Datatable } from 'src/plugins/expressions'; +import { createEscapeValue } from './escape_value'; export const LINE_FEED_CHARACTER = '\r\n'; -const nonAlphaNumRE = /[^a-zA-Z0-9]/; -const allDoubleQuoteRE = /"/g; export const CSV_MIME_TYPE = 'text/plain;charset=utf-8'; -// TODO: enhance this later on -function escape(val: object | string, quoteValues: boolean) { - if (val != null && typeof val === 'object') { - val = val.valueOf(); - } - - val = String(val); - - if (quoteValues && nonAlphaNumRE.test(val)) { - val = `"${val.replace(allDoubleQuoteRE, '""')}"`; - } - - return val; -} - interface CSVOptions { csvSeparator: string; quoteValues: boolean; + escapeFormulaValues: boolean; formatFactory: FormatFactory; raw?: boolean; } export function datatableToCSV( { columns, rows }: Datatable, - { csvSeparator, quoteValues, formatFactory, raw }: CSVOptions + { csvSeparator, quoteValues, formatFactory, raw, escapeFormulaValues }: CSVOptions ) { + const escapeValues = createEscapeValue(quoteValues, escapeFormulaValues); // Build the header row by its names - const header = columns.map((col) => escape(col.name, quoteValues)); + const header = columns.map((col) => escapeValues(col.name)); const formatters = columns.reduce>>( (memo, { id, meta }) => { @@ -56,7 +42,7 @@ export function datatableToCSV( // Convert the array of row objects to an array of row arrays const csvRows = rows.map((row) => { return columns.map((column) => - escape(raw ? row[column.id] : formatters[column.id].convert(row[column.id]), quoteValues) + escapeValues(raw ? row[column.id] : formatters[column.id].convert(row[column.id])) ); }); diff --git a/src/plugins/data/common/exports/formula_checks.ts b/src/plugins/data/common/exports/formula_checks.ts new file mode 100644 index 0000000000000..eed339c15781c --- /dev/null +++ b/src/plugins/data/common/exports/formula_checks.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 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 { startsWith } from 'lodash'; +import { Datatable } from 'src/plugins/expressions'; +import { CSV_FORMULA_CHARS } from './constants'; + +export const cellHasFormulas = (val: string) => + CSV_FORMULA_CHARS.some((formulaChar) => startsWith(val, formulaChar)); + +export const tableHasFormulas = (columns: Datatable['columns'], rows: Datatable['rows']) => { + return ( + columns.some(({ name }) => cellHasFormulas(name)) || + rows.some((row) => columns.some(({ id }) => cellHasFormulas(row[id]))) + ); +}; diff --git a/src/plugins/data/common/exports/index.ts b/src/plugins/data/common/exports/index.ts index 9e6fb10fae84c..1dbc4a17091bc 100644 --- a/src/plugins/data/common/exports/index.ts +++ b/src/plugins/data/common/exports/index.ts @@ -7,3 +7,6 @@ */ export { datatableToCSV, CSV_MIME_TYPE } from './export_csv'; +export { createEscapeValue } from './escape_value'; +export { CSV_FORMULA_CHARS } from './constants'; +export { cellHasFormulas, tableHasFormulas } from './formula_checks'; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 9af1cbf95d94d..51f3d9fd660e5 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -209,10 +209,12 @@ export { * Exporters (CSV) */ -import { datatableToCSV, CSV_MIME_TYPE } from '../common'; +import { datatableToCSV, CSV_MIME_TYPE, cellHasFormulas, tableHasFormulas } from '../common'; export const exporters = { datatableToCSV, CSV_MIME_TYPE, + cellHasFormulas, + tableHasFormulas, }; /* diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index 4508ad5948927..276320eb1a6ab 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -927,6 +927,8 @@ export type ExistsFilter = Filter & { export const exporters: { datatableToCSV: typeof datatableToCSV; CSV_MIME_TYPE: string; + cellHasFormulas: (val: string) => boolean; + tableHasFormulas: (columns: import("../../expressions").DatatableColumn[], rows: Record[]) => boolean; }; // Warning: (ae-missing-release-tag) "ExpressionFunctionKibana" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -2777,25 +2779,25 @@ export interface WaitUntilNextSessionCompletesOptions { // src/plugins/data/public/index.ts:170:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:170:26 - (ae-forgotten-export) The symbol "HistogramFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/public/index.ts:213:23 - (ae-forgotten-export) The symbol "datatableToCSV" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:238:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:410:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:410:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:410:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:412:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:413:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:422:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:423:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:424:1 - (ae-forgotten-export) The symbol "IpAddress" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:425:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:429:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:430:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:433:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:434:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts -// src/plugins/data/public/index.ts:437:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:240:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:240:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:240:27 - (ae-forgotten-export) The symbol "validateIndexPattern" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:240:27 - (ae-forgotten-export) The symbol "flattenHitWrapper" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:240:27 - (ae-forgotten-export) The symbol "formatHitProvider" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:412:20 - (ae-forgotten-export) The symbol "getResponseInspectorStats" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:412:20 - (ae-forgotten-export) The symbol "tabifyAggResponse" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:412:20 - (ae-forgotten-export) The symbol "tabifyGetColumns" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:414:1 - (ae-forgotten-export) The symbol "CidrMask" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:415:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:424:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:425:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:426:1 - (ae-forgotten-export) The symbol "IpAddress" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:427:1 - (ae-forgotten-export) The symbol "isDateHistogramBucketAggConfig" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:431:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:432:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:435:1 - (ae-forgotten-export) The symbol "parseInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:436:1 - (ae-forgotten-export) The symbol "propFilter" needs to be exported by the entry point index.d.ts +// src/plugins/data/public/index.ts:439:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // src/plugins/data/public/query/state_sync/connect_to_query_state.ts:34:5 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts // src/plugins/data/public/search/session/session_service.ts:62:5 - (ae-forgotten-export) The symbol "UrlGeneratorStateMapping" needs to be exported by the entry point index.d.ts diff --git a/src/plugins/data/public/utils/table_inspector_view/components/data_view.test.tsx b/src/plugins/data/public/utils/table_inspector_view/components/data_view.test.tsx index 4b5a80e9b0743..e6b40bcb5936c 100644 --- a/src/plugins/data/public/utils/table_inspector_view/components/data_view.test.tsx +++ b/src/plugins/data/public/utils/table_inspector_view/components/data_view.test.tsx @@ -16,6 +16,7 @@ jest.mock('../../../../../share/public', () => ({ })); jest.mock('../../../../common', () => ({ datatableToCSV: jest.fn().mockReturnValue('csv'), + tableHasFormulas: jest.fn().mockReturnValue(false), })); describe('Inspector Data View', () => { diff --git a/src/plugins/data/public/utils/table_inspector_view/components/download_options.tsx b/src/plugins/data/public/utils/table_inspector_view/components/download_options.tsx index 07230a29ca3f5..e79a1c2b52e03 100644 --- a/src/plugins/data/public/utils/table_inspector_view/components/download_options.tsx +++ b/src/plugins/data/public/utils/table_inspector_view/components/download_options.tsx @@ -7,12 +7,19 @@ */ import React, { Component } from 'react'; +import { memoize } from 'lodash'; import PropTypes from 'prop-types'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { EuiButton, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; -import { CSV_MIME_TYPE, datatableToCSV } from '../../../../common'; +import { + EuiButton, + EuiContextMenuItem, + EuiContextMenuPanel, + EuiPopover, + EuiToolTip, +} from '@elastic/eui'; +import { CSV_MIME_TYPE, datatableToCSV, tableHasFormulas } from '../../../../common'; import { Datatable } from '../../../../../expressions'; import { downloadMultipleAs } from '../../../../../share/public'; import { FieldFormatsStart } from '../../../field_formats'; @@ -30,6 +37,10 @@ interface DataDownloadOptionsProps { fieldFormats: FieldFormatsStart; } +const detectFormulasInTables = memoize((datatables: Datatable[]) => + datatables.some(({ columns, rows }) => tableHasFormulas(columns, rows)) +); + class DataDownloadOptions extends Component { static propTypes = { title: PropTypes.string.isRequired, @@ -74,6 +85,7 @@ class DataDownloadOptions extends Component ); + const downloadButton = detectedFormulasInTables ? ( + + {button} + + ) : ( + button + ); + const items = [ > = {}; input.rows.forEach((row) => { const bucketIdentifier = getBucketIdentifier(row, by); - const accumulatorValue = accumulators[bucketIdentifier] ?? 0; + const accumulatorValue = accumulators[bucketIdentifier]; const currentValue = row[inputColumnId]; if (currentValue != null) { @@ -135,22 +135,35 @@ export const overallMetric: ExpressionFunctionOverallMetric = { valueCounter[bucketIdentifier] = (valueCounter[bucketIdentifier] ?? 0) + currentNumberValues.length; case 'sum': - accumulators[bucketIdentifier] = - accumulatorValue + currentNumberValues.reduce((a, b) => a + b, 0); + accumulators[bucketIdentifier] = currentNumberValues.reduce( + (a, b) => a + b, + accumulatorValue || 0 + ); break; case 'min': - accumulators[bucketIdentifier] = Math.min(accumulatorValue, ...currentNumberValues); + if (typeof accumulatorValue !== 'undefined') { + accumulators[bucketIdentifier] = Math.min(accumulatorValue, ...currentNumberValues); + } else { + accumulators[bucketIdentifier] = Math.min(...currentNumberValues); + } break; case 'max': - accumulators[bucketIdentifier] = Math.max(accumulatorValue, ...currentNumberValues); + if (typeof accumulatorValue !== 'undefined') { + accumulators[bucketIdentifier] = Math.max(accumulatorValue, ...currentNumberValues); + } else { + accumulators[bucketIdentifier] = Math.max(...currentNumberValues); + } break; } } }); if (metric === 'average') { Object.keys(accumulators).forEach((bucketIdentifier) => { - accumulators[bucketIdentifier] = - accumulators[bucketIdentifier]! / valueCounter[bucketIdentifier]!; + const accumulatorValue = accumulators[bucketIdentifier]; + const valueCount = valueCounter[bucketIdentifier]; + if (typeof accumulatorValue !== 'undefined' && typeof valueCount !== 'undefined') { + accumulators[bucketIdentifier] = accumulatorValue / valueCount; + } }); } return { diff --git a/src/plugins/expressions/common/expression_functions/specs/tests/overall_metric.test.ts b/src/plugins/expressions/common/expression_functions/specs/tests/overall_metric.test.ts index 30354c4e54dc7..94bd3a7edba5d 100644 --- a/src/plugins/expressions/common/expression_functions/specs/tests/overall_metric.test.ts +++ b/src/plugins/expressions/common/expression_functions/specs/tests/overall_metric.test.ts @@ -16,12 +16,12 @@ describe('interpreter/functions#overall_metric', () => { const runFn = (input: Datatable, args: OverallMetricArgs) => fn(input, args, {} as ExecutionContext) as Datatable; - it('calculates overall sum', () => { + it('ignores null or undefined with sum', () => { const result = runFn( { type: 'datatable', columns: [{ id: 'val', name: 'val', meta: { type: 'number' } }], - rows: [{ val: 5 }, { val: 7 }, { val: 3 }, { val: 2 }], + rows: [{ val: undefined }, { val: 7 }, { val: 3 }, { val: 2 }], }, { inputColumnId: 'val', outputColumnId: 'output', metric: 'sum' } ); @@ -30,10 +30,10 @@ describe('interpreter/functions#overall_metric', () => { name: 'output', meta: { type: 'number' }, }); - expect(result.rows.map((row) => row.output)).toEqual([17, 17, 17, 17]); + expect(result.rows.map((row) => row.output)).toEqual([12, 12, 12, 12]); }); - it('ignores null or undefined', () => { + it('ignores null or undefined with average', () => { const result = runFn( { type: 'datatable', @@ -50,6 +50,40 @@ describe('interpreter/functions#overall_metric', () => { expect(result.rows.map((row) => row.output)).toEqual([3, 3, 3, 3, 3]); }); + it('ignores null or undefined with min', () => { + const result = runFn( + { + type: 'datatable', + columns: [{ id: 'val', name: 'val', meta: { type: 'number' } }], + rows: [{}, { val: null }, { val: undefined }, { val: 1 }, { val: 5 }], + }, + { inputColumnId: 'val', outputColumnId: 'output', metric: 'min' } + ); + expect(result.columns).toContainEqual({ + id: 'output', + name: 'output', + meta: { type: 'number' }, + }); + expect(result.rows.map((row) => row.output)).toEqual([1, 1, 1, 1, 1]); + }); + + it('ignores null or undefined with max', () => { + const result = runFn( + { + type: 'datatable', + columns: [{ id: 'val', name: 'val', meta: { type: 'number' } }], + rows: [{}, { val: null }, { val: undefined }, { val: -1 }, { val: -5 }], + }, + { inputColumnId: 'val', outputColumnId: 'output', metric: 'max' } + ); + expect(result.columns).toContainEqual({ + id: 'output', + name: 'output', + meta: { type: 'number' }, + }); + expect(result.rows.map((row) => row.output)).toEqual([-1, -1, -1, -1, -1]); + }); + it('calculates overall sum for multiple series', () => { const result = runFn( { @@ -103,18 +137,9 @@ describe('interpreter/functions#overall_metric', () => { { val: 8, split: 'B' }, ], }, - { inputColumnId: 'val', outputColumnId: 'output', by: ['split'], metric: 'sum' } + { inputColumnId: 'val', outputColumnId: 'output', by: ['split'], metric: 'min' } ); - expect(result.rows.map((row) => row.output)).toEqual([ - 1 + 4 + 6, - 2 + 7 + 8, - 3 + 5, - 1 + 4 + 6, - 3 + 5, - 1 + 4 + 6, - 2 + 7 + 8, - 2 + 7 + 8, - ]); + expect(result.rows.map((row) => row.output)).toEqual([1, 2, 3, 1, 3, 1, 2, 2]); }); it('treats null like undefined and empty string for split columns', () => { @@ -162,6 +187,24 @@ describe('interpreter/functions#overall_metric', () => { metric: 'max', }); expect(result2.rows.map((row) => row.output)).toEqual([6, 8, 9, 6, 9, 6, 9, 8, 9]); + + const result3 = runFn(table, { + inputColumnId: 'val', + outputColumnId: 'output', + by: ['split'], + metric: 'average', + }); + expect(result3.rows.map((row) => row.output)).toEqual([ + (1 + 4 + 6) / 3, + (2 + 8) / 2, + (3 + 5 + 7 + 9) / 4, + (1 + 4 + 6) / 3, + (3 + 5 + 7 + 9) / 4, + (1 + 4 + 6) / 3, + (3 + 5 + 7 + 9) / 4, + (2 + 8) / 2, + (3 + 5 + 7 + 9) / 4, + ]); }); it('handles array values', () => { diff --git a/src/plugins/vis_type_table/public/components/table_vis_controls.tsx b/src/plugins/vis_type_table/public/components/table_vis_controls.tsx index 61d3330402169..458bca4a54061 100644 --- a/src/plugins/vis_type_table/public/components/table_vis_controls.tsx +++ b/src/plugins/vis_type_table/public/components/table_vis_controls.tsx @@ -7,7 +7,13 @@ */ import React, { memo, useState, useCallback } from 'react'; -import { EuiButtonEmpty, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; +import { + EuiButtonEmpty, + EuiContextMenuItem, + EuiContextMenuPanel, + EuiPopover, + EuiToolTip, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; @@ -39,6 +45,8 @@ export const TableVisControls = memo( services: { uiSettings }, } = useKibana(); + const detectedFormulasInTable = exporters.tableHasFormulas(columns, rows); + const onClickExport = useCallback( (formatted: boolean) => { const csvSeparator = uiSettings.get(CSV_SEPARATOR_SETTING); @@ -55,6 +63,7 @@ export const TableVisControls = memo( quoteValues, formatFactory: getFormatService().deserialize, raw: !formatted, + escapeFormulaValues: false, } ); downloadFileAs(`${filename || 'unsaved'}.csv`, { content, type: exporters.CSV_MIME_TYPE }); @@ -85,6 +94,20 @@ export const TableVisControls = memo( ); + const downloadButton = detectedFormulasInTable ? ( + + {button} + + ) : ( + button + ); + const items = [ onClickExport(false)}> @@ -100,7 +123,7 @@ export const TableVisControls = memo( return ( { - if (!start || !end || !transactionType) { + if (!start || !end) { return; } return callApmApi({ @@ -33,19 +31,11 @@ export function useInstanceDetailsFetcher({ serviceName, serviceNodeName, }, - query: { start, end, transactionType, environment, kuery }, + query: { start, end }, }, }); }, - [ - serviceName, - serviceNodeName, - start, - end, - transactionType, - environment, - kuery, - ] + [serviceName, serviceNodeName, start, end] ); return { data, status }; diff --git a/x-pack/plugins/apm/server/index.ts b/x-pack/plugins/apm/server/index.ts index 9031f454f4a7f..b6dd22c528e99 100644 --- a/x-pack/plugins/apm/server/index.ts +++ b/x-pack/plugins/apm/server/index.ts @@ -40,9 +40,7 @@ export const config = { schema.literal(SearchAggregatedTransactionSetting.always), schema.literal(SearchAggregatedTransactionSetting.never), ], - { - defaultValue: SearchAggregatedTransactionSetting.never, - } + { defaultValue: SearchAggregatedTransactionSetting.auto } ), telemetryCollectionEnabled: schema.boolean({ defaultValue: true }), metricsInterval: schema.number({ defaultValue: 30 }), diff --git a/x-pack/plugins/apm/server/lib/observability_overview/get_transactions_per_minute.ts b/x-pack/plugins/apm/server/lib/observability_overview/get_transactions_per_minute.ts index c74e910e8cd27..90cef471c38af 100644 --- a/x-pack/plugins/apm/server/lib/observability_overview/get_transactions_per_minute.ts +++ b/x-pack/plugins/apm/server/lib/observability_overview/get_transactions_per_minute.ts @@ -12,7 +12,10 @@ import { import { TRANSACTION_TYPE } from '../../../common/elasticsearch_fieldnames'; import { rangeQuery } from '../../../../observability/server'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; -import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; +import { + getDocumentTypeFilterForAggregatedTransactions, + getProcessorEventForAggregatedTransactions, +} from '../helpers/aggregated_transactions'; import { calculateThroughput } from '../helpers/calculate_throughput'; export async function getTransactionsPerMinute({ @@ -40,7 +43,12 @@ export async function getTransactionsPerMinute({ size: 0, query: { bool: { - filter: rangeQuery(start, end), + filter: [ + ...rangeQuery(start, end), + ...getDocumentTypeFilterForAggregatedTransactions( + searchAggregatedTransactions + ), + ], }, }, aggs: { diff --git a/x-pack/plugins/apm/server/lib/services/get_service_instance_metadata_details.ts b/x-pack/plugins/apm/server/lib/services/get_service_instance_metadata_details.ts index 44dfc2f600efc..1479b0fdbb73c 100644 --- a/x-pack/plugins/apm/server/lib/services/get_service_instance_metadata_details.ts +++ b/x-pack/plugins/apm/server/lib/services/get_service_instance_metadata_details.ts @@ -4,16 +4,20 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import { merge } from 'lodash'; +import { ProcessorEvent } from '../../../common/processor_event'; import { + METRICSET_NAME, SERVICE_NAME, SERVICE_NODE_NAME, - TRANSACTION_TYPE, } from '../../../common/elasticsearch_fieldnames'; -import { kqlQuery, rangeQuery } from '../../../../observability/server'; -import { environmentQuery } from '../../../common/utils/environment_query'; -import { getProcessorEventForAggregatedTransactions } from '../helpers/aggregated_transactions'; +import { rangeQuery } from '../../../../observability/server'; import { Setup, SetupTimeRange } from '../helpers/setup_request'; +import { maybe } from '../../../common/utils/maybe'; +import { + getDocumentTypeFilterForAggregatedTransactions, + getProcessorEventForAggregatedTransactions, +} from '../helpers/aggregated_transactions'; export interface KeyValue { key: string; @@ -24,53 +28,100 @@ export async function getServiceInstanceMetadataDetails({ serviceName, serviceNodeName, setup, - searchAggregatedTransactions, - transactionType, - environment, - kuery, }: { serviceName: string; serviceNodeName: string; setup: Setup & SetupTimeRange; - searchAggregatedTransactions: boolean; - transactionType: string; - environment?: string; - kuery?: string; }) { const { start, end, apmEventClient } = setup; const filter = [ { term: { [SERVICE_NAME]: serviceName } }, { term: { [SERVICE_NODE_NAME]: serviceNodeName } }, - { term: { [TRANSACTION_TYPE]: transactionType } }, ...rangeQuery(start, end), - ...environmentQuery(environment), - ...kqlQuery(kuery), ]; - const response = await apmEventClient.search( - 'get_service_instance_metadata_details', - { - apm: { - events: [ - getProcessorEventForAggregatedTransactions( - searchAggregatedTransactions - ), - ], - }, - body: { - terminate_after: 1, - size: 1, - query: { bool: { filter } }, - }, - } - ); + async function getApplicationMetricSample() { + const response = await apmEventClient.search( + 'get_service_instance_metadata_details_application_metric', + { + apm: { + events: [ProcessorEvent.metric], + }, + body: { + terminate_after: 1, + size: 1, + query: { + bool: { + filter: filter.concat({ term: { [METRICSET_NAME]: 'app' } }), + }, + }, + }, + } + ); + + return maybe(response.hits.hits[0]?._source); + } - const sample = response.hits.hits[0]?._source; + async function getTransactionEventSample() { + const response = await apmEventClient.search( + 'get_service_instance_metadata_details_application_transaction_event', + { + apm: { + events: [ProcessorEvent.transaction], + }, + body: { + terminate_after: 1, + size: 1, + query: { bool: { filter } }, + }, + } + ); - if (!sample) { - return {}; + return maybe(response.hits.hits[0]?._source); } + async function getTransactionMetricSample() { + const response = await apmEventClient.search( + 'get_service_instance_metadata_details_application_transaction_metric', + { + apm: { + events: [getProcessorEventForAggregatedTransactions(true)], + }, + body: { + terminate_after: 1, + size: 1, + query: { + bool: { + filter: filter.concat( + getDocumentTypeFilterForAggregatedTransactions(true) + ), + }, + }, + }, + } + ); + return maybe(response.hits.hits[0]?._source); + } + + // we can expect the most detail of application metrics, + // followed by transaction events, and then finally transaction metrics + const [ + applicationMetricSample, + transactionEventSample, + transactionMetricSample, + ] = await Promise.all([ + getApplicationMetricSample(), + getTransactionEventSample(), + getTransactionMetricSample(), + ]); + + const sample = merge( + {}, + transactionMetricSample, + transactionEventSample, + applicationMetricSample + ); + const { agent, service, container, kubernetes, host, cloud } = sample; return { diff --git a/x-pack/plugins/apm/server/routes/services.ts b/x-pack/plugins/apm/server/routes/services.ts index 3329119726bb5..400fdd8bb67c0 100644 --- a/x-pack/plugins/apm/server/routes/services.ts +++ b/x-pack/plugins/apm/server/routes/services.ts @@ -584,32 +584,17 @@ export const serviceInstancesMetadataDetails = createApmServerRoute({ serviceName: t.string, serviceNodeName: t.string, }), - query: t.intersection([ - t.type({ transactionType: t.string }), - environmentRt, - kueryRt, - rangeRt, - ]), + query: rangeRt, }), options: { tags: ['access:apm'] }, handler: async (resources) => { const setup = await setupRequest(resources); const { serviceName, serviceNodeName } = resources.params.path; - const { transactionType, environment, kuery } = resources.params.query; - - const searchAggregatedTransactions = await getSearchAggregatedTransactions({ - ...setup, - kuery, - }); return await getServiceInstanceMetadataDetails({ - searchAggregatedTransactions, setup, serviceName, serviceNodeName, - transactionType, - environment, - kuery, }); }, }); diff --git a/x-pack/plugins/fleet/common/openapi/README.md b/x-pack/plugins/fleet/common/openapi/README.md index 4afbef549f248..7ccccf052f37d 100644 --- a/x-pack/plugins/fleet/common/openapi/README.md +++ b/x-pack/plugins/fleet/common/openapi/README.md @@ -16,8 +16,8 @@ For example, online viewers for the specification like these: * It's currently generated with: ``` - npx swagger-cli bundle -o bundled.json -t json entrypoint.yaml - npx swagger-cli bundle -o bundled.yaml -t yaml entrypoint.yaml + npx @redocly/openapi-cli bundle --ext yaml --output bundled.yaml entrypoint.yaml + npx @redocly/openapi-cli bundle --ext json --output bundled.json entrypoint.yaml ``` * [Paths](paths/README.md): this defines each endpoint. A path can have one operation per http method. * [Components](components/README.md): Reusable components like [`schemas`](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#schemaObject), diff --git a/x-pack/plugins/fleet/common/openapi/bundled.json b/x-pack/plugins/fleet/common/openapi/bundled.json index b121095c8b91b..9ec519365ea22 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.json +++ b/x-pack/plugins/fleet/common/openapi/bundled.json @@ -1,13 +1,16 @@ { "openapi": "3.0.0", + "tags": [], "info": { - "title": "Ingest Manager", + "title": "Fleet", + "description": "OpenAPI schema for Fleet API endpoints", "version": "0.2", "contact": { - "name": "Ingest Team" + "name": "Fleet Team" }, "license": { - "name": "Elastic" + "name": "Elastic License 2.0", + "url": "https://www.elastic.co/licensing/elastic-license" } }, "servers": [ @@ -17,9 +20,9 @@ } ], "paths": { - "/agent_policies": { - "get": { - "summary": "Agent policy - List", + "/setup": { + "post": { + "summary": "Setup", "tags": [], "responses": { "200": { @@ -29,67 +32,102 @@ "schema": { "type": "object", "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/paths/~1agent_policies/post/responses/200/content/application~1json/schema/properties/item" - } - }, - "total": { - "type": "number" - }, - "page": { - "type": "number" - }, - "perPage": { - "type": "number" + "isInitialized": { + "type": "boolean" } - }, - "required": [ - "items", - "total", - "page", - "perPage" - ] + } + } + } + } + }, + "500": { + "description": "Internal Server Error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } } } } } }, - "operationId": "agent-policy-list", + "operationId": "post-setup", "parameters": [ { - "name": "perPage", - "in": "query", - "description": "The number of items to return", - "required": false, - "schema": { - "type": "integer", - "default": 50 - } - }, - { - "name": "page", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "default": 1 + "$ref": "#/components/parameters/kbn_xsrf" + } + ] + } + }, + "/epm/categories": { + "get": { + "summary": "Packages - Categories", + "tags": [], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "count": { + "type": "number" + } + }, + "required": [ + "id", + "title", + "count" + ] + } + } + } } - }, - { - "name": "kuery", - "in": "query", - "required": false, - "schema": { - "type": "string" + } + }, + "operationId": "get-epm-categories" + } + }, + "/epm/packages": { + "get": { + "summary": "Packages - List", + "tags": [], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/search_result" + } + } + } } } - ], - "description": "" + }, + "operationId": "get-epm-list" }, - "post": { - "summary": "Agent policy - Create", + "parameters": [] + }, + "/epm/packages/{pkgkey}": { + "get": { + "summary": "Packages - Info", "tags": [], "responses": { "200": { @@ -98,110 +136,57 @@ "application/json": { "schema": { "type": "object", - "properties": { - "item": { - "allOf": [ - { - "$ref": "#/paths/~1agent_policies/post/requestBody/content/application~1json/schema" - }, - { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "status": { - "type": "string", - "enum": [ - "active", - "inactive" - ] - }, - "packagePolicies": { - "oneOf": [ - { - "items": { - "type": "string" - } - }, - { - "items": { - "$ref": "#/paths/~1package_policies~1%7BpackagePolicyId%7D/get/responses/200/content/application~1json/schema/properties/item" - } - } - ], - "type": "array" - }, - "updated_on": { - "type": "string", - "format": "date-time" - }, - "updated_by": { - "type": "string" - }, - "revision": { - "type": "number" - }, - "agents": { - "type": "number" - } - }, - "required": [ - "id", - "status" + "allOf": [ + { + "properties": { + "response": { + "$ref": "#/components/schemas/package_info" + } + } + }, + { + "properties": { + "status": { + "type": "string", + "enum": [ + "installed", + "not_installed" ] + }, + "savedObject": { + "type": "string" } + }, + "required": [ + "status", + "savedObject" ] } - } - } - } - } - } - }, - "operationId": "post-agent-policy", - "requestBody": { - "content": { - "application/json": { - "schema": { - "title": "NewAgentPolicy", - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "namespace": { - "type": "string" - }, - "description": { - "type": "string" - } + ] } } } } }, - "security": [], - "parameters": [ + "operationId": "get-epm-package-pkgkey", + "security": [ { - "$ref": "#/paths/~1setup/post/parameters/0" + "basicAuth": [] } ] - } - }, - "/agent_policies/{agentPolicyId}": { + }, "parameters": [ { "schema": { "type": "string" }, - "name": "agentPolicyId", + "name": "pkgkey", "in": "path", "required": true } ], - "get": { - "summary": "Agent policy - Info", + "post": { + "summary": "Packages - Install", "tags": [], "responses": { "200": { @@ -211,24 +196,43 @@ "schema": { "type": "object", "properties": { - "item": { - "$ref": "#/paths/~1agent_policies/post/responses/200/content/application~1json/schema/properties/item" + "response": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "id", + "type" + ] + } } }, "required": [ - "item" + "response" ] } } } } }, - "operationId": "agent-policy-info", - "description": "Get one agent policy", - "parameters": [] + "operationId": "post-epm-install-pkgkey", + "description": "", + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + } + ] }, - "put": { - "summary": "Agent policy - Update", + "delete": { + "summary": "Packages - Delete", "tags": [], "responses": { "200": { @@ -238,49 +242,89 @@ "schema": { "type": "object", "properties": { - "item": { - "$ref": "#/paths/~1agent_policies/post/responses/200/content/application~1json/schema/properties/item" + "response": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "id", + "type" + ] + } } }, "required": [ - "item" + "response" ] } } } } }, - "operationId": "put-agent-policy-agentPolicyId", + "operationId": "post-epm-delete-pkgkey", + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + } + ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/paths/~1agent_policies/post/requestBody/content/application~1json/schema" + "type": "object", + "properties": { + "force": { + "type": "boolean" + } + } } } } - }, - "parameters": [ - { - "$ref": "#/paths/~1setup/post/parameters/0" - } - ] + } } }, - "/agent_policies/{agentPolicyId}/copy": { - "parameters": [ - { - "schema": { - "type": "string" - }, - "name": "agentPolicyId", - "in": "path", - "required": true - } - ], + "/agents/setup": { + "get": { + "summary": "Agents setup - Info", + "tags": [], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "isInitialized": { + "type": "boolean" + } + }, + "required": [ + "isInitialized" + ] + } + } + } + } + }, + "operationId": "get-agents-setup", + "security": [ + { + "basicAuth": [] + } + ] + }, "post": { - "summary": "Agent policy - copy one policy", - "operationId": "agent-policy-copy", + "summary": "Agents setup - Create", + "operationId": "post-agents-setup", "responses": { "200": { "description": "OK", @@ -289,12 +333,12 @@ "schema": { "type": "object", "properties": { - "item": { - "$ref": "#/paths/~1agent_policies/post/responses/200/content/application~1json/schema/properties/item" + "isInitialized": { + "type": "boolean" } }, "required": [ - "item" + "isInitialized" ] } } @@ -307,85 +351,80 @@ "schema": { "type": "object", "properties": { - "name": { + "admin_username": { "type": "string" }, - "description": { + "admin_password": { "type": "string" } }, "required": [ - "name" + "admin_username", + "admin_password" ] } } - }, - "description": "" + } }, - "description": "Copies one agent policy" + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + } + ] } }, - "/agent_policies/delete": { - "post": { - "summary": "Agent policy - Delete", - "operationId": "post-agent-policy-delete", + "/agent-status": { + "get": { + "summary": "Agents - Summary stats", + "tags": [], "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "success": { - "type": "boolean" - } + "type": "object", + "properties": { + "error": { + "type": "integer" }, - "required": [ - "id", - "success" - ] - } - } - } - } - } - }, - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "agentPolicyIds": { - "type": "array", - "items": { - "type": "string" + "events": { + "type": "integer" + }, + "inactive": { + "type": "integer" + }, + "offline": { + "type": "integer" + }, + "online": { + "type": "integer" + }, + "other": { + "type": "integer" + }, + "total": { + "type": "integer" + }, + "updating": { + "type": "integer" } - } + }, + "required": [ + "error", + "events", + "inactive", + "offline", + "online", + "other", + "total", + "updating" + ] } } } } }, - "parameters": [ - { - "$ref": "#/paths/~1setup/post/parameters/0" - } - ] - }, - "parameters": [] - }, - "/agent-status": { - "get": { - "summary": "Fleet - Agent - Status for policy", - "tags": [], - "responses": {}, "operationId": "get-fleet-agent-status", "parameters": [ { @@ -401,7 +440,7 @@ }, "/agents": { "get": { - "summary": "Fleet - Agent - List", + "summary": "Agents - List", "tags": [], "responses": { "200": { @@ -414,7 +453,7 @@ "list": { "type": "array", "items": { - "type": "object" + "$ref": "#/components/schemas/agent" } }, "total": { @@ -446,47 +485,51 @@ ] } }, - "/agents/{agentId}/unenroll": { - "parameters": [ - { - "schema": { - "type": "string" - }, - "name": "agentId", - "in": "path", - "required": true - } - ], + "/agents/bulk_upgrade": { "post": { - "summary": "Fleet - Agent - Unenroll", + "summary": "Agents - Bulk Upgrade", "tags": [], - "responses": {}, - "operationId": "post-fleet-agents-unenroll", + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/bulk_upgrade_agents" + } + } + } + }, + "400": { + "description": "BAD REQUEST", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/upgrade_agent" + } + } + } + } + }, + "operationId": "post-fleet-agents-bulk-upgrade", "parameters": [ { - "$ref": "#/paths/~1setup/post/parameters/0" + "$ref": "#/components/parameters/kbn_xsrf" } ], "requestBody": { + "required": true, "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "revoke": { - "type": "boolean" - }, - "force": { - "type": "boolean" - } - } + "$ref": "#/components/schemas/bulk_upgrade_agents" } } } } } }, - "/agents/{agentId}/upgrade": { + "/agents/{agentId}": { "parameters": [ { "schema": { @@ -497,8 +540,8 @@ "required": true } ], - "post": { - "summary": "Fleet - Agent - Upgrade", + "get": { + "summary": "Agent - Info", "tags": [], "responses": { "200": { @@ -506,70 +549,54 @@ "content": { "application/json": { "schema": { - "$ref": "#/paths/~1agents~1%7BagentId%7D~1upgrade/post/requestBody/content/application~1json/schema" + "type": "object", + "properties": { + "item": { + "$ref": "#/components/schemas/agent" + } + }, + "required": [ + "item" + ] } } } - }, - "400": { - "description": "BAD REQUEST", + } + }, + "operationId": "get-fleet-agents-agentId" + }, + "put": { + "summary": "Agent - Update", + "tags": [], + "responses": { + "200": { + "description": "OK", "content": { "application/json": { "schema": { - "$ref": "#/paths/~1agents~1%7BagentId%7D~1upgrade/post/requestBody/content/application~1json/schema" + "type": "object", + "properties": { + "item": { + "$ref": "#/components/schemas/agent" + } + }, + "required": [ + "item" + ] } } } } }, - "operationId": "post-fleet-agents-upgrade", + "operationId": "put-fleet-agents-agentId", "parameters": [ { - "$ref": "#/paths/~1setup/post/parameters/0" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "title": "UpgradeAgent", - "oneOf": [ - { - "type": "object", - "properties": { - "version": { - "type": "string" - } - }, - "required": [ - "version" - ] - }, - { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "source_uri": { - "type": "string" - } - }, - "required": [ - "version" - ] - } - ] - } - } + "$ref": "#/components/parameters/kbn_xsrf" } - } - } - }, - "/agents/bulk_upgrade": { - "post": { - "summary": "Fleet - Agent - Bulk Upgrade", + ] + }, + "delete": { + "summary": "Agent - Delete", "tags": [], "responses": { "200": { @@ -577,102 +604,163 @@ "content": { "application/json": { "schema": { - "$ref": "#/paths/~1agents~1bulk_upgrade/post/requestBody/content/application~1json/schema" - } - } - } - }, - "400": { - "description": "BAD REQUEST", - "content": { - "application/json": { - "schema": { - "$ref": "#/paths/~1agents~1%7BagentId%7D~1upgrade/post/requestBody/content/application~1json/schema" + "type": "object", + "properties": { + "action": { + "type": "string", + "enum": [ + "deleted" + ] + } + }, + "required": [ + "action" + ] } } } } }, - "operationId": "post-fleet-agents-bulk-upgrade", + "operationId": "delete-fleet-agents-agentId", + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + } + ] + } + }, + "/agents/{agentId}/unenroll": { + "parameters": [ + { + "schema": { + "type": "string" + }, + "name": "agentId", + "in": "path", + "required": true + } + ], + "post": { + "summary": "Agent - Unenroll", + "tags": [], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "400": { + "description": "BAD REQUEST", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "message": { + "type": "string" + }, + "statusCode": { + "type": "number", + "enum": [ + 400 + ] + } + } + } + } + } + } + }, + "operationId": "post-fleet-agents-unenroll", "parameters": [ { - "$ref": "#/paths/~1setup/post/parameters/0" + "$ref": "#/components/parameters/kbn_xsrf" } ], "requestBody": { - "required": true, "content": { "application/json": { "schema": { - "title": "BulkUpgradeAgents", - "oneOf": [ - { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "agents": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "version", - "agents" - ] - }, - { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "source_uri": { - "type": "string" - }, - "agents": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "version", - "agents" - ] + "type": "object", + "properties": { + "revoke": { + "type": "boolean" }, - { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "source_uri": { - "type": "string" - }, - "agents": { - "type": "string" - } - }, - "required": [ - "version", - "agents" - ] + "force": { + "type": "boolean" } - ] + } } } } } } }, - "/agents/setup": { + "/agents/{agentId}/upgrade": { + "parameters": [ + { + "schema": { + "type": "string" + }, + "name": "agentId", + "in": "path", + "required": true + } + ], + "post": { + "summary": "Agent - Upgrade", + "tags": [], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/upgrade_agent" + } + } + } + }, + "400": { + "description": "BAD REQUEST", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/upgrade_agent" + } + } + } + } + }, + "operationId": "post-fleet-agents-upgrade", + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/upgrade_agent" + } + } + } + } + } + }, + "/agent_policies": { "get": { - "summary": "Agents setup - Info", + "summary": "Agent policies - List", "tags": [], "responses": { "200": { @@ -682,28 +770,50 @@ "schema": { "type": "object", "properties": { - "isInitialized": { - "type": "boolean" + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/agent_policy" + } + }, + "total": { + "type": "number" + }, + "page": { + "type": "number" + }, + "perPage": { + "type": "number" } }, "required": [ - "isInitialized" + "items", + "total", + "page", + "perPage" ] } } } } }, - "operationId": "get-agents-setup", - "security": [ + "operationId": "agent-policy-list", + "parameters": [ { - "basicAuth": [] + "$ref": "#/components/parameters/page_size" + }, + { + "$ref": "#/components/parameters/page_index" + }, + { + "$ref": "#/components/parameters/kuery" } - ] + ], + "description": "" }, "post": { - "summary": "Agents setup - Create", - "operationId": "post-agents-setup", + "summary": "Agent policy - Create", + "tags": [], "responses": { "200": { "description": "OK", @@ -712,98 +822,46 @@ "schema": { "type": "object", "properties": { - "isInitialized": { - "type": "boolean" + "item": { + "$ref": "#/components/schemas/agent_policy" } - }, - "required": [ - "isInitialized" - ] + } } } } } }, + "operationId": "post-agent-policy", "requestBody": { "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "admin_username": { - "type": "string" - }, - "admin_password": { - "type": "string" - } - }, - "required": [ - "admin_username", - "admin_password" - ] + "$ref": "#/components/schemas/new_agent_policy" } } } }, + "security": [], "parameters": [ { - "$ref": "#/paths/~1setup/post/parameters/0" - } - ] - } - }, - "/enrollment-api-keys": { - "get": { - "summary": "Enrollment - List", - "tags": [], - "responses": {}, - "operationId": "get-fleet-enrollment-api-keys", - "parameters": [] - }, - "post": { - "summary": "Enrollment - Create", - "tags": [], - "responses": {}, - "operationId": "post-fleet-enrollment-api-keys", - "parameters": [ - { - "$ref": "#/paths/~1setup/post/parameters/0" + "$ref": "#/components/parameters/kbn_xsrf" } ] } }, - "/enrollment-api-keys/{keyId}": { + "/agent_policies/{agentPolicyId}": { "parameters": [ { "schema": { "type": "string" }, - "name": "keyId", + "name": "agentPolicyId", "in": "path", "required": true } ], "get": { - "summary": "Enrollment - Info", - "tags": [], - "responses": {}, - "operationId": "get-fleet-enrollment-api-keys-keyId" - }, - "delete": { - "summary": "Enrollment - Delete", - "tags": [], - "responses": {}, - "operationId": "delete-fleet-enrollment-api-keys-keyId", - "parameters": [ - { - "$ref": "#/paths/~1setup/post/parameters/0" - } - ] - } - }, - "/epm/categories": { - "get": { - "summary": "EPM - Categories", + "summary": "Agent policy - Info", "tags": [], "responses": { "200": { @@ -811,104 +869,26 @@ "content": { "application/json": { "schema": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "title": { - "type": "string" - }, - "count": { - "type": "number" - } - }, - "required": [ - "id", - "title", - "count" - ] - } - } - } - } - } - }, - "operationId": "get-epm-categories" - } - }, - "/epm/packages": { - "get": { - "summary": "EPM - Packages - List", - "tags": [], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "title": "SearchResult", - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "download": { - "type": "string" - }, - "icons": { - "type": "string" - }, - "name": { - "type": "string" - }, - "path": { - "type": "string" - }, - "title": { - "type": "string" - }, - "type": { - "type": "string" - }, - "version": { - "type": "string" - }, - "status": { - "type": "string" - }, - "savedObject": { - "type": "object" - } - }, - "required": [ - "description", - "download", - "icons", - "name", - "path", - "title", - "type", - "version", - "status" - ] - } + "type": "object", + "properties": { + "item": { + "$ref": "#/components/schemas/agent_policy" + } + }, + "required": [ + "item" + ] } } } } }, - "operationId": "get-epm-list" + "operationId": "agent-policy-info", + "description": "Get one agent policy", + "parameters": [] }, - "parameters": [] - }, - "/epm/packages/{pkgkey}": { - "get": { - "summary": "EPM - Packages - Info", + "put": { + "summary": "Agent policy - Update", "tags": [], "responses": { "200": { @@ -917,233 +897,50 @@ "application/json": { "schema": { "type": "object", - "allOf": [ - { - "properties": { - "response": { - "title": "PackageInfo", - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "title": { - "type": "string" - }, - "version": { - "type": "string" - }, - "readme": { - "type": "string" - }, - "description": { - "type": "string" - }, - "type": { - "type": "string" - }, - "categories": { - "type": "array", - "items": { - "type": "string" - } - }, - "requirement": { - "oneOf": [ - { - "properties": { - "kibana": { - "type": "object", - "properties": { - "versions": { - "type": "string" - } - } - } - } - }, - { - "properties": { - "elasticsearch": { - "type": "object", - "properties": { - "versions": { - "type": "string" - } - } - } - } - } - ], - "type": "object" - }, - "screenshots": { - "type": "array", - "items": { - "type": "object", - "properties": { - "src": { - "type": "string" - }, - "path": { - "type": "string" - }, - "title": { - "type": "string" - }, - "size": { - "type": "string" - }, - "type": { - "type": "string" - } - }, - "required": [ - "src", - "path" - ] - } - }, - "icons": { - "type": "array", - "items": { - "type": "string" - } - }, - "assets": { - "type": "array", - "items": { - "type": "string" - } - }, - "internal": { - "type": "boolean" - }, - "format_version": { - "type": "string" - }, - "data_streams": { - "type": "array", - "items": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "name": { - "type": "string" - }, - "release": { - "type": "string" - }, - "ingeset_pipeline": { - "type": "string" - }, - "vars": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "default": { - "type": "string" - } - }, - "required": [ - "name", - "default" - ] - } - }, - "type": { - "type": "string" - }, - "package": { - "type": "string" - } - }, - "required": [ - "title", - "name", - "release", - "ingeset_pipeline", - "type", - "package" - ] - } - }, - "download": { - "type": "string" - }, - "path": { - "type": "string" - }, - "removable": { - "type": "boolean" - } - }, - "required": [ - "name", - "title", - "version", - "description", - "type", - "categories", - "requirement", - "assets", - "format_version", - "download", - "path" - ] - } - } - }, - { - "properties": { - "status": { - "type": "string", - "enum": [ - "installed", - "not_installed" - ] - }, - "savedObject": { - "type": "string" - } - }, - "required": [ - "status", - "savedObject" - ] + "properties": { + "item": { + "$ref": "#/components/schemas/agent_policy" } + }, + "required": [ + "item" ] } } } } }, - "operationId": "get-epm-package-pkgkey", - "security": [ + "operationId": "put-agent-policy-agentPolicyId", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/new_agent_policy" + } + } + } + }, + "parameters": [ { - "basicAuth": [] + "$ref": "#/components/parameters/kbn_xsrf" } ] - }, + } + }, + "/agent_policies/{agentPolicyId}/copy": { "parameters": [ { "schema": { "type": "string" }, - "name": "pkgkey", + "name": "agentPolicyId", "in": "path", "required": true } ], "post": { - "summary": "EPM - Packages - Install", - "tags": [], + "summary": "Agent policy - copy one policy", + "operationId": "agent-policy-copy", "responses": { "200": { "description": "OK", @@ -1152,114 +949,101 @@ "schema": { "type": "object", "properties": { - "response": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string" - } - }, - "required": [ - "id", - "type" - ] - } + "item": { + "$ref": "#/components/schemas/agent_policy" } }, "required": [ - "response" + "item" ] } } } } }, - "operationId": "post-epm-install-pkgkey", - "description": "", - "parameters": [ - { - "$ref": "#/paths/~1setup/post/parameters/0" - } - ] - }, - "delete": { - "summary": "EPM - Packages - Delete", - "tags": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "name" + ] + } + } + }, + "description": "" + }, + "description": "Copies one agent policy" + } + }, + "/agent_policies/delete": { + "post": { + "summary": "Agent policy - Delete", + "operationId": "post-agent-policy-delete", "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "response": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "type": { - "type": "string" - } - }, - "required": [ - "id", - "type" - ] + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "success": { + "type": "boolean" } - } - }, - "required": [ - "response" - ] + }, + "required": [ + "id", + "success" + ] + } } } } } }, - "operationId": "post-epm-delete-pkgkey", - "parameters": [ - { - "$ref": "#/paths/~1setup/post/parameters/0" - } - ], "requestBody": { "content": { "application/json": { "schema": { "type": "object", "properties": { - "force": { - "type": "boolean" + "agentPolicyIds": { + "type": "array", + "items": { + "type": "string" + } } } } } } - } - } + }, + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + } + ] + }, + "parameters": [] }, - "/agents/{agentId}": { - "parameters": [ - { - "schema": { - "type": "string" - }, - "name": "agentId", - "in": "path", - "required": true - } - ], + "/enrollment-api-keys": { "get": { - "summary": "Fleet - Agent - Info", + "summary": "Enrollment API Keys - List", "tags": [], "responses": { "200": { @@ -1269,64 +1053,143 @@ "schema": { "type": "object", "properties": { - "item": { - "type": "object" - } + "list": { + "type": "array", + "items": { + "$ref": "#/components/schemas/enrollment_api_key" + } + }, + "page": { + "type": "number" + }, + "perPage": { + "type": "number" + }, + "total": { + "type": "number" + } }, "required": [ - "item" + "list", + "page", + "perPage", + "total" ] } } } } }, - "operationId": "get-fleet-agents-agentId" + "operationId": "get-fleet-enrollment-api-keys", + "parameters": [] }, - "put": { - "summary": "Fleet - Agent - Update", + "post": { + "summary": "Enrollment API Key - Create", "tags": [], - "responses": {}, - "operationId": "put-fleet-agents-agentId", - "parameters": [ - { - "$ref": "#/paths/~1setup/post/parameters/0" + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "item": { + "$ref": "#/components/schemas/enrollment_api_key" + }, + "action": { + "type": "string", + "enum": [ + "created" + ] + } + } + } + } + } } - ] - }, - "delete": { - "summary": "Fleet - Agent - Delete", - "tags": [], - "responses": {}, - "operationId": "delete-fleet-agents-agentId", + }, + "operationId": "post-fleet-enrollment-api-keys", "parameters": [ { - "$ref": "#/paths/~1setup/post/parameters/0" + "$ref": "#/components/parameters/kbn_xsrf" } ] } }, - "/install/{osType}": { + "/enrollment-api-keys/{keyId}": { "parameters": [ { "schema": { "type": "string" }, - "name": "osType", + "name": "keyId", "in": "path", "required": true } ], "get": { - "summary": "Fleet - Get OS install script", + "summary": "Enrollment API Key - Info", "tags": [], - "responses": {}, - "operationId": "get-fleet-install-osType" + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "item": { + "$ref": "#/components/schemas/enrollment_api_key" + } + }, + "required": [ + "item" + ] + } + } + } + } + }, + "operationId": "get-fleet-enrollment-api-keys-keyId" + }, + "delete": { + "summary": "Enrollment API Key - Delete", + "tags": [], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "action": { + "type": "string", + "enum": [ + "deleted" + ] + } + }, + "required": [ + "action" + ] + } + } + } + } + }, + "operationId": "delete-fleet-enrollment-api-keys-keyId", + "parameters": [ + { + "$ref": "#/components/parameters/kbn_xsrf" + } + ] } }, "/package_policies": { "get": { - "summary": "PackagePolicies - List", + "summary": "Package policies - List", "tags": [], "responses": { "200": { @@ -1339,7 +1202,7 @@ "items": { "type": "array", "items": { - "$ref": "#/paths/~1package_policies~1%7BpackagePolicyId%7D/get/responses/200/content/application~1json/schema/properties/item" + "$ref": "#/components/schemas/package_policy" } }, "total": { @@ -1366,7 +1229,7 @@ }, "parameters": [], "post": { - "summary": "PackagePolicies - Create", + "summary": "Package policy - Create", "operationId": "post-packagePolicies", "responses": { "200": { @@ -1377,103 +1240,21 @@ "content": { "application/json": { "schema": { - "title": "NewPackagePolicy", - "type": "object", - "description": "", - "properties": { - "enabled": { - "type": "boolean" - }, - "package": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "version": { - "type": "string" - }, - "title": { - "type": "string" - } - }, - "required": [ - "name", - "version", - "title" - ] - }, - "namespace": { - "type": "string" - }, - "output_id": { - "type": "string" - }, - "inputs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "type": { - "type": "string" - }, - "enabled": { - "type": "boolean" - }, - "processors": { - "type": "array", - "items": { - "type": "string" - } - }, - "streams": { - "type": "array", - "items": {} - }, - "config": { - "type": "object" - }, - "vars": { - "type": "object" - } - }, - "required": [ - "type", - "enabled", - "streams" - ] - } - }, - "policy_id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - } - }, - "required": [ - "output_id", - "inputs", - "policy_id", - "name" - ] + "$ref": "#/components/schemas/new_package_policy" } } } }, "parameters": [ { - "$ref": "#/paths/~1setup/post/parameters/0" + "$ref": "#/components/parameters/kbn_xsrf" } ] } }, "/package_policies/{packagePolicyId}": { "get": { - "summary": "PackagePolicies - Info", + "summary": "Package policy - Info", "tags": [], "responses": { "200": { @@ -1484,31 +1265,7 @@ "type": "object", "properties": { "item": { - "title": "PackagePolicy", - "allOf": [ - { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "revision": { - "type": "number" - }, - "inputs": { - "type": "array", - "items": {} - } - }, - "required": [ - "id", - "revision" - ] - }, - { - "$ref": "#/paths/~1package_policies/post/requestBody/content/application~1json/schema" - } - ] + "$ref": "#/components/schemas/package_policy" } }, "required": [ @@ -1532,26 +1289,13 @@ } ], "put": { - "summary": "PackagePolicies - Update", + "summary": "Package policy - Update", "operationId": "put-packagePolicies-packagePolicyId", "requestBody": { "content": { "application/json": { "schema": { - "title": "UpdatePackagePolicy", - "allOf": [ - { - "type": "object", - "properties": { - "version": { - "type": "string" - } - } - }, - { - "$ref": "#/paths/~1package_policies/post/requestBody/content/application~1json/schema" - } - ] + "$ref": "#/components/schemas/update_package_policy" } } } @@ -1565,7 +1309,7 @@ "type": "object", "properties": { "item": { - "$ref": "#/paths/~1package_policies~1%7BpackagePolicyId%7D/get/responses/200/content/application~1json/schema/properties/item" + "$ref": "#/components/schemas/package_policy" }, "sucess": { "type": "boolean" @@ -1582,78 +1326,705 @@ }, "parameters": [ { - "$ref": "#/paths/~1setup/post/parameters/0" + "$ref": "#/components/parameters/kbn_xsrf" } ] } + } + }, + "components": { + "securitySchemes": { + "basicAuth": { + "type": "http", + "scheme": "basic" + }, + "Enrollment_API_Key": { + "name": "Authorization", + "type": "apiKey", + "in": "header", + "description": "e.g. Authorization: ApiKey base64EnrollmentApiKey" + }, + "Access_API_Key": { + "name": "Authorization", + "type": "apiKey", + "in": "header", + "description": "e.g. Authorization: ApiKey base64AccessApiKey" + } }, - "/setup": { - "post": { - "summary": "Ingest Manager - Setup", - "tags": [], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "isInitialized": { - "type": "boolean" + "parameters": { + "kbn_xsrf": { + "schema": { + "type": "string" + }, + "in": "header", + "name": "kbn-xsrf", + "required": true + }, + "page_size": { + "name": "perPage", + "in": "query", + "description": "The number of items to return", + "required": false, + "schema": { + "type": "integer", + "default": 50 + } + }, + "page_index": { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + "kuery": { + "name": "kuery", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + }, + "schemas": { + "search_result": { + "title": "SearchResult", + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "download": { + "type": "string" + }, + "icons": { + "type": "string" + }, + "name": { + "type": "string" + }, + "path": { + "type": "string" + }, + "title": { + "type": "string" + }, + "type": { + "type": "string" + }, + "version": { + "type": "string" + }, + "status": { + "type": "string" + }, + "savedObject": { + "type": "object" + } + }, + "required": [ + "description", + "download", + "icons", + "name", + "path", + "title", + "type", + "version", + "status" + ] + }, + "package_info": { + "title": "PackageInfo", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "title": { + "type": "string" + }, + "version": { + "type": "string" + }, + "readme": { + "type": "string" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string" + }, + "categories": { + "type": "array", + "items": { + "type": "string" + } + }, + "requirement": { + "oneOf": [ + { + "properties": { + "kibana": { + "type": "object", + "properties": { + "versions": { + "type": "string" + } + } + } + } + }, + { + "properties": { + "elasticsearch": { + "type": "object", + "properties": { + "versions": { + "type": "string" + } } } } } + ], + "type": "object" + }, + "screenshots": { + "type": "array", + "items": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "path": { + "type": "string" + }, + "title": { + "type": "string" + }, + "size": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "src", + "path" + ] } }, - "500": { - "description": "Internal Server Error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string" - } + "icons": { + "type": "array", + "items": { + "type": "string" + } + }, + "assets": { + "type": "array", + "items": { + "type": "string" + } + }, + "internal": { + "type": "boolean" + }, + "format_version": { + "type": "string" + }, + "data_streams": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "name": { + "type": "string" + }, + "release": { + "type": "string" + }, + "ingeset_pipeline": { + "type": "string" + }, + "vars": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "default": { + "type": "string" + } + }, + "required": [ + "name", + "default" + ] } + }, + "type": { + "type": "string" + }, + "package": { + "type": "string" + } + }, + "required": [ + "title", + "name", + "release", + "ingeset_pipeline", + "type", + "package" + ] + } + }, + "download": { + "type": "string" + }, + "path": { + "type": "string" + }, + "removable": { + "type": "boolean" + } + }, + "required": [ + "name", + "title", + "version", + "description", + "type", + "categories", + "requirement", + "assets", + "format_version", + "download", + "path" + ] + }, + "agent_type": { + "type": "string", + "title": "AgentType", + "enum": [ + "PERMANENT", + "EPHEMERAL", + "TEMPORARY" + ] + }, + "agent_metadata": { + "title": "AgentMetadata", + "type": "object" + }, + "agent_status": { + "type": "string", + "title": "AgentStatus", + "enum": [ + "offline", + "error", + "online", + "inactive", + "warning" + ] + }, + "agent": { + "title": "Agent", + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/agent_type" + }, + "active": { + "type": "boolean" + }, + "enrolled_at": { + "type": "string" + }, + "unenrolled_at": { + "type": "string" + }, + "unenrollment_started_at": { + "type": "string" + }, + "shared_id": { + "type": "string", + "deprecated": true + }, + "access_api_key_id": { + "type": "string" + }, + "default_api_key_id": { + "type": "string" + }, + "policy_id": { + "type": "string" + }, + "policy_revision": { + "type": "number" + }, + "last_checkin": { + "type": "string" + }, + "user_provided_metadata": { + "$ref": "#/components/schemas/agent_metadata" + }, + "local_metadata": { + "$ref": "#/components/schemas/agent_metadata" + }, + "id": { + "type": "string" + }, + "access_api_key": { + "type": "string" + }, + "status": { + "$ref": "#/components/schemas/agent_status" + }, + "default_api_key": { + "type": "string" + } + }, + "required": [ + "type", + "active", + "enrolled_at", + "id", + "status" + ] + }, + "bulk_upgrade_agents": { + "title": "BulkUpgradeAgents", + "oneOf": [ + { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "agents": { + "type": "array", + "items": { + "type": "string" } } + }, + "required": [ + "version", + "agents" + ] + }, + { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "source_uri": { + "type": "string" + }, + "agents": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "version", + "agents" + ] + }, + { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "source_uri": { + "type": "string" + }, + "agents": { + "type": "string" + } + }, + "required": [ + "version", + "agents" + ] + } + ] + }, + "upgrade_agent": { + "title": "UpgradeAgent", + "oneOf": [ + { + "type": "object", + "properties": { + "version": { + "type": "string" + } + }, + "required": [ + "version" + ] + }, + { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "source_uri": { + "type": "string" + } + }, + "required": [ + "version" + ] + } + ] + }, + "new_agent_policy": { + "title": "NewAgentPolicy", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "new_package_policy": { + "title": "NewPackagePolicy", + "type": "object", + "description": "", + "properties": { + "enabled": { + "type": "boolean" + }, + "package": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "title": { + "type": "string" + } + }, + "required": [ + "name", + "version", + "title" + ] + }, + "namespace": { + "type": "string" + }, + "output_id": { + "type": "string" + }, + "inputs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "processors": { + "type": "array", + "items": { + "type": "string" + } + }, + "streams": { + "type": "array", + "items": {} + }, + "config": { + "type": "object" + }, + "vars": { + "type": "object" + } + }, + "required": [ + "type", + "enabled", + "streams" + ] } + }, + "policy_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" } }, - "operationId": "post-setup", - "parameters": [ + "required": [ + "output_id", + "inputs", + "policy_id", + "name" + ] + }, + "package_policy": { + "title": "PackagePolicy", + "allOf": [ { - "schema": { - "type": "string" + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "revision": { + "type": "number" + }, + "inputs": { + "type": "array", + "items": {} + } }, - "in": "header", - "name": "kbn-xsrf", - "required": true + "required": [ + "id", + "revision" + ] + }, + { + "$ref": "#/components/schemas/new_package_policy" } ] - } - } - }, - "components": { - "securitySchemes": { - "basicAuth": { - "type": "http", - "scheme": "basic" }, - "Enrollment API Key": { - "name": "Authorization", - "type": "apiKey", - "in": "header", - "description": "e.g. Authorization: ApiKey base64EnrollmentApiKey" + "agent_policy": { + "allOf": [ + { + "$ref": "#/components/schemas/new_agent_policy" + }, + { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "status": { + "type": "string", + "enum": [ + "active", + "inactive" + ] + }, + "packagePolicies": { + "oneOf": [ + { + "items": { + "type": "string" + } + }, + { + "items": { + "$ref": "#/components/schemas/package_policy" + } + } + ], + "type": "array" + }, + "updated_on": { + "type": "string", + "format": "date-time" + }, + "updated_by": { + "type": "string" + }, + "revision": { + "type": "number" + }, + "agents": { + "type": "number" + } + }, + "required": [ + "id", + "status" + ] + } + ] }, - "Access API Key": { - "name": "Authorization", - "type": "apiKey", - "in": "header", - "description": "e.g. Authorization: ApiKey base64AccessApiKey" + "enrollment_api_key": { + "title": "EnrollmentApiKey", + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "api_key_id": { + "type": "string" + }, + "api_key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "active": { + "type": "boolean" + }, + "policy_id": { + "type": "string" + }, + "created_at": { + "type": "string" + } + }, + "required": [ + "id", + "api_key_id", + "api_key", + "active", + "created_at" + ] + }, + "update_package_policy": { + "title": "UpdatePackagePolicy", + "allOf": [ + { + "type": "object", + "properties": { + "version": { + "type": "string" + } + } + }, + { + "$ref": "#/components/schemas/new_package_policy" + } + ] } } }, @@ -1662,4 +2033,4 @@ "basicAuth": [] } ] -} +} \ No newline at end of file diff --git a/x-pack/plugins/fleet/common/openapi/bundled.yaml b/x-pack/plugins/fleet/common/openapi/bundled.yaml index 537ef136c7611..a5d177e9a0f18 100644 --- a/x-pack/plugins/fleet/common/openapi/bundled.yaml +++ b/x-pack/plugins/fleet/common/openapi/bundled.yaml @@ -1,18 +1,21 @@ openapi: 3.0.0 +tags: [] info: - title: Ingest Manager + title: Fleet + description: OpenAPI schema for Fleet API endpoints version: '0.2' contact: - name: Ingest Team + name: Fleet Team license: - name: Elastic + name: Elastic License 2.0 + url: 'https://www.elastic.co/licensing/elastic-license' servers: - url: 'http://localhost:5601/api/fleet' description: local paths: - /agent_policies: - get: - summary: Agent policy - List + /setup: + post: + summary: Setup tags: [] responses: '200': @@ -22,44 +25,63 @@ paths: schema: type: object properties: - items: - type: array - items: - $ref: '#/paths/~1agent_policies/post/responses/200/content/application~1json/schema/properties/item' - total: - type: number - page: - type: number - perPage: - type: number - required: - - items - - total - - page - - perPage - operationId: agent-policy-list + isInitialized: + type: boolean + '500': + description: Internal Server Error + content: + application/json: + schema: + type: object + properties: + message: + type: string + operationId: post-setup parameters: - - name: perPage - in: query - description: The number of items to return - required: false - schema: - type: integer - default: 50 - - name: page - in: query - required: false - schema: - type: integer - default: 1 - - name: kuery - in: query - required: false - schema: - type: string - description: '' - post: - summary: Agent policy - Create + - $ref: '#/components/parameters/kbn_xsrf' + /epm/categories: + get: + summary: Packages - Categories + tags: [] + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: string + title: + type: string + count: + type: number + required: + - id + - title + - count + operationId: get-epm-categories + /epm/packages: + get: + summary: Packages - List + tags: [] + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/search_result' + operationId: get-epm-list + parameters: [] + '/epm/packages/{pkgkey}': + get: + summary: Packages - Info tags: [] responses: '200': @@ -68,64 +90,32 @@ paths: application/json: schema: type: object - properties: - item: - allOf: - - $ref: '#/paths/~1agent_policies/post/requestBody/content/application~1json/schema' - - type: object - properties: - id: - type: string - status: - type: string - enum: - - active - - inactive - packagePolicies: - oneOf: - - items: - type: string - - items: - $ref: '#/paths/~1package_policies~1%7BpackagePolicyId%7D/get/responses/200/content/application~1json/schema/properties/item' - type: array - updated_on: - type: string - format: date-time - updated_by: - type: string - revision: - type: number - agents: - type: number - required: - - id - - status - operationId: post-agent-policy - requestBody: - content: - application/json: - schema: - title: NewAgentPolicy - type: object - properties: - name: - type: string - namespace: - type: string - description: - type: string - security: [] - parameters: - - $ref: '#/paths/~1setup/post/parameters/0' - '/agent_policies/{agentPolicyId}': + allOf: + - properties: + response: + $ref: '#/components/schemas/package_info' + - properties: + status: + type: string + enum: + - installed + - not_installed + savedObject: + type: string + required: + - status + - savedObject + operationId: get-epm-package-pkgkey + security: + - basicAuth: [] parameters: - schema: type: string - name: agentPolicyId + name: pkgkey in: path required: true - get: - summary: Agent policy - Info + post: + summary: Packages - Install tags: [] responses: '200': @@ -135,15 +125,26 @@ paths: schema: type: object properties: - item: - $ref: '#/paths/~1agent_policies/post/responses/200/content/application~1json/schema/properties/item' + response: + type: array + items: + type: object + properties: + id: + type: string + type: + type: string + required: + - id + - type required: - - item - operationId: agent-policy-info - description: Get one agent policy - parameters: [] - put: - summary: Agent policy - Update + - response + operationId: post-epm-install-pkgkey + description: '' + parameters: + - $ref: '#/components/parameters/kbn_xsrf' + delete: + summary: Packages - Delete tags: [] responses: '200': @@ -153,28 +154,53 @@ paths: schema: type: object properties: - item: - $ref: '#/paths/~1agent_policies/post/responses/200/content/application~1json/schema/properties/item' + response: + type: array + items: + type: object + properties: + id: + type: string + type: + type: string + required: + - id + - type required: - - item - operationId: put-agent-policy-agentPolicyId + - response + operationId: post-epm-delete-pkgkey + parameters: + - $ref: '#/components/parameters/kbn_xsrf' requestBody: content: application/json: schema: - $ref: '#/paths/~1agent_policies/post/requestBody/content/application~1json/schema' - parameters: - - $ref: '#/paths/~1setup/post/parameters/0' - '/agent_policies/{agentPolicyId}/copy': - parameters: - - schema: - type: string - name: agentPolicyId - in: path - required: true + type: object + properties: + force: + type: boolean + /agents/setup: + get: + summary: Agents setup - Info + tags: [] + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + isInitialized: + type: boolean + required: + - isInitialized + operationId: get-agents-setup + security: + - basicAuth: [] post: - summary: Agent policy - copy one policy - operationId: agent-policy-copy + summary: Agents setup - Create + operationId: post-agents-setup responses: '200': description: OK @@ -183,73 +209,168 @@ paths: schema: type: object properties: - item: - $ref: '#/paths/~1agent_policies/post/responses/200/content/application~1json/schema/properties/item' + isInitialized: + type: boolean required: - - item + - isInitialized requestBody: content: application/json: schema: type: object properties: - name: + admin_username: type: string - description: + admin_password: type: string required: - - name - description: '' - description: Copies one agent policy - /agent_policies/delete: + - admin_username + - admin_password + parameters: + - $ref: '#/components/parameters/kbn_xsrf' + /agent-status: + get: + summary: Agents - Summary stats + tags: [] + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + error: + type: integer + events: + type: integer + inactive: + type: integer + offline: + type: integer + online: + type: integer + other: + type: integer + total: + type: integer + updating: + type: integer + required: + - error + - events + - inactive + - offline + - online + - other + - total + - updating + operationId: get-fleet-agent-status + parameters: + - schema: + type: string + name: policyId + in: query + required: false + /agents: + get: + summary: Agents - List + tags: [] + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + list: + type: array + items: + $ref: '#/components/schemas/agent' + total: + type: number + page: + type: number + perPage: + type: number + required: + - list + - total + - page + - perPage + operationId: get-fleet-agents + security: + - basicAuth: [] + /agents/bulk_upgrade: post: - summary: Agent policy - Delete - operationId: post-agent-policy-delete + summary: Agents - Bulk Upgrade + tags: [] responses: '200': description: OK content: application/json: schema: - type: array - items: - type: object - properties: - id: - type: string - success: - type: boolean - required: - - id - - success + $ref: '#/components/schemas/bulk_upgrade_agents' + '400': + description: BAD REQUEST + content: + application/json: + schema: + $ref: '#/components/schemas/upgrade_agent' + operationId: post-fleet-agents-bulk-upgrade + parameters: + - $ref: '#/components/parameters/kbn_xsrf' requestBody: + required: true content: application/json: schema: - type: object - properties: - agentPolicyIds: - type: array - items: - type: string - parameters: - - $ref: '#/paths/~1setup/post/parameters/0' - parameters: [] - /agent-status: + $ref: '#/components/schemas/bulk_upgrade_agents' + '/agents/{agentId}': + parameters: + - schema: + type: string + name: agentId + in: path + required: true get: - summary: Fleet - Agent - Status for policy + summary: Agent - Info + tags: [] + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + item: + $ref: '#/components/schemas/agent' + required: + - item + operationId: get-fleet-agents-agentId + put: + summary: Agent - Update tags: [] - responses: {} - operationId: get-fleet-agent-status + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + item: + $ref: '#/components/schemas/agent' + required: + - item + operationId: put-fleet-agents-agentId parameters: - - schema: - type: string - name: policyId - in: query - required: false - /agents: - get: - summary: Fleet - Agent - List + - $ref: '#/components/parameters/kbn_xsrf' + delete: + summary: Agent - Delete tags: [] responses: '200': @@ -259,24 +380,15 @@ paths: schema: type: object properties: - list: - type: array - items: - type: object - total: - type: number - page: - type: number - perPage: - type: number + action: + type: string + enum: + - deleted required: - - list - - total - - page - - perPage - operationId: get-fleet-agents - security: - - basicAuth: [] + - action + operationId: delete-fleet-agents-agentId + parameters: + - $ref: '#/components/parameters/kbn_xsrf' '/agents/{agentId}/unenroll': parameters: - schema: @@ -285,12 +397,33 @@ paths: in: path required: true post: - summary: Fleet - Agent - Unenroll + summary: Agent - Unenroll tags: [] - responses: {} + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + '400': + description: BAD REQUEST + content: + application/json: + schema: + type: object + properties: + error: + type: string + message: + type: string + statusCode: + type: number + enum: + - 400 operationId: post-fleet-agents-unenroll parameters: - - $ref: '#/paths/~1setup/post/parameters/0' + - $ref: '#/components/parameters/kbn_xsrf' requestBody: content: application/json: @@ -309,7 +442,7 @@ paths: in: path required: true post: - summary: Fleet - Agent - Upgrade + summary: Agent - Upgrade tags: [] responses: '200': @@ -317,40 +450,25 @@ paths: content: application/json: schema: - $ref: '#/paths/~1agents~1%7BagentId%7D~1upgrade/post/requestBody/content/application~1json/schema' + $ref: '#/components/schemas/upgrade_agent' '400': description: BAD REQUEST content: application/json: schema: - $ref: '#/paths/~1agents~1%7BagentId%7D~1upgrade/post/requestBody/content/application~1json/schema' + $ref: '#/components/schemas/upgrade_agent' operationId: post-fleet-agents-upgrade parameters: - - $ref: '#/paths/~1setup/post/parameters/0' + - $ref: '#/components/parameters/kbn_xsrf' requestBody: required: true content: application/json: schema: - title: UpgradeAgent - oneOf: - - type: object - properties: - version: - type: string - required: - - version - - type: object - properties: - version: - type: string - source_uri: - type: string - required: - - version - /agents/bulk_upgrade: - post: - summary: Fleet - Agent - Bulk Upgrade + $ref: '#/components/schemas/upgrade_agent' + /agent_policies: + get: + summary: Agent policies - List tags: [] responses: '200': @@ -358,61 +476,60 @@ paths: content: application/json: schema: - $ref: '#/paths/~1agents~1bulk_upgrade/post/requestBody/content/application~1json/schema' - '400': - description: BAD REQUEST + type: object + properties: + items: + type: array + items: + $ref: '#/components/schemas/agent_policy' + total: + type: number + page: + type: number + perPage: + type: number + required: + - items + - total + - page + - perPage + operationId: agent-policy-list + parameters: + - $ref: '#/components/parameters/page_size' + - $ref: '#/components/parameters/page_index' + - $ref: '#/components/parameters/kuery' + description: '' + post: + summary: Agent policy - Create + tags: [] + responses: + '200': + description: OK content: application/json: schema: - $ref: '#/paths/~1agents~1%7BagentId%7D~1upgrade/post/requestBody/content/application~1json/schema' - operationId: post-fleet-agents-bulk-upgrade - parameters: - - $ref: '#/paths/~1setup/post/parameters/0' + type: object + properties: + item: + $ref: '#/components/schemas/agent_policy' + operationId: post-agent-policy requestBody: - required: true content: application/json: schema: - title: BulkUpgradeAgents - oneOf: - - type: object - properties: - version: - type: string - agents: - type: array - items: - type: string - required: - - version - - agents - - type: object - properties: - version: - type: string - source_uri: - type: string - agents: - type: array - items: - type: string - required: - - version - - agents - - type: object - properties: - version: - type: string - source_uri: - type: string - agents: - type: string - required: - - version - - agents - /agents/setup: + $ref: '#/components/schemas/new_agent_policy' + security: [] + parameters: + - $ref: '#/components/parameters/kbn_xsrf' + '/agent_policies/{agentPolicyId}': + parameters: + - schema: + type: string + name: agentPolicyId + in: path + required: true get: - summary: Agents setup - Info + summary: Agent policy - Info tags: [] responses: '200': @@ -422,16 +539,16 @@ paths: schema: type: object properties: - isInitialized: - type: boolean + item: + $ref: '#/components/schemas/agent_policy' required: - - isInitialized - operationId: get-agents-setup - security: - - basicAuth: [] - post: - summary: Agents setup - Create - operationId: post-agents-setup + - item + operationId: agent-policy-info + description: Get one agent policy + parameters: [] + put: + summary: Agent policy - Update + tags: [] responses: '200': description: OK @@ -440,87 +557,58 @@ paths: schema: type: object properties: - isInitialized: - type: boolean + item: + $ref: '#/components/schemas/agent_policy' required: - - isInitialized + - item + operationId: put-agent-policy-agentPolicyId requestBody: content: application/json: schema: - type: object - properties: - admin_username: - type: string - admin_password: - type: string - required: - - admin_username - - admin_password - parameters: - - $ref: '#/paths/~1setup/post/parameters/0' - /enrollment-api-keys: - get: - summary: Enrollment - List - tags: [] - responses: {} - operationId: get-fleet-enrollment-api-keys - parameters: [] - post: - summary: Enrollment - Create - tags: [] - responses: {} - operationId: post-fleet-enrollment-api-keys + $ref: '#/components/schemas/new_agent_policy' parameters: - - $ref: '#/paths/~1setup/post/parameters/0' - '/enrollment-api-keys/{keyId}': + - $ref: '#/components/parameters/kbn_xsrf' + '/agent_policies/{agentPolicyId}/copy': parameters: - schema: type: string - name: keyId + name: agentPolicyId in: path required: true - get: - summary: Enrollment - Info - tags: [] - responses: {} - operationId: get-fleet-enrollment-api-keys-keyId - delete: - summary: Enrollment - Delete - tags: [] - responses: {} - operationId: delete-fleet-enrollment-api-keys-keyId - parameters: - - $ref: '#/paths/~1setup/post/parameters/0' - /epm/categories: - get: - summary: EPM - Categories - tags: [] + post: + summary: Agent policy - copy one policy + operationId: agent-policy-copy responses: '200': description: OK content: application/json: schema: - type: array - items: - type: object - properties: - id: - type: string - title: - type: string - count: - type: number - required: - - id - - title - - count - operationId: get-epm-categories - /epm/packages: - get: - summary: EPM - Packages - List - tags: [] + type: object + properties: + item: + $ref: '#/components/schemas/agent_policy' + required: + - item + requestBody: + content: + application/json: + schema: + type: object + properties: + name: + type: string + description: + type: string + required: + - name + description: '' + description: Copies one agent policy + /agent_policies/delete: + post: + summary: Agent policy - Delete + operationId: post-agent-policy-delete responses: '200': description: OK @@ -529,195 +617,31 @@ paths: schema: type: array items: - title: SearchResult type: object properties: - description: - type: string - download: - type: string - icons: - type: string - name: - type: string - path: - type: string - title: - type: string - type: - type: string - version: - type: string - status: + id: type: string - savedObject: - type: object + success: + type: boolean required: - - description - - download - - icons - - name - - path - - title - - type - - version - - status - operationId: get-epm-list + - id + - success + requestBody: + content: + application/json: + schema: + type: object + properties: + agentPolicyIds: + type: array + items: + type: string + parameters: + - $ref: '#/components/parameters/kbn_xsrf' parameters: [] - '/epm/packages/{pkgkey}': + /enrollment-api-keys: get: - summary: EPM - Packages - Info - tags: [] - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - allOf: - - properties: - response: - title: PackageInfo - type: object - properties: - name: - type: string - title: - type: string - version: - type: string - readme: - type: string - description: - type: string - type: - type: string - categories: - type: array - items: - type: string - requirement: - oneOf: - - properties: - kibana: - type: object - properties: - versions: - type: string - - properties: - elasticsearch: - type: object - properties: - versions: - type: string - type: object - screenshots: - type: array - items: - type: object - properties: - src: - type: string - path: - type: string - title: - type: string - size: - type: string - type: - type: string - required: - - src - - path - icons: - type: array - items: - type: string - assets: - type: array - items: - type: string - internal: - type: boolean - format_version: - type: string - data_streams: - type: array - items: - type: object - properties: - title: - type: string - name: - type: string - release: - type: string - ingeset_pipeline: - type: string - vars: - type: array - items: - type: object - properties: - name: - type: string - default: - type: string - required: - - name - - default - type: - type: string - package: - type: string - required: - - title - - name - - release - - ingeset_pipeline - - type - - package - download: - type: string - path: - type: string - removable: - type: boolean - required: - - name - - title - - version - - description - - type - - categories - - requirement - - assets - - format_version - - download - - path - - properties: - status: - type: string - enum: - - installed - - not_installed - savedObject: - type: string - required: - - status - - savedObject - operationId: get-epm-package-pkgkey - security: - - basicAuth: [] - parameters: - - schema: - type: string - name: pkgkey - in: path - required: true - post: - summary: EPM - Packages - Install + summary: Enrollment API Keys - List tags: [] responses: '200': @@ -727,26 +651,25 @@ paths: schema: type: object properties: - response: + list: type: array items: - type: object - properties: - id: - type: string - type: - type: string - required: - - id - - type + $ref: '#/components/schemas/enrollment_api_key' + page: + type: number + perPage: + type: number + total: + type: number required: - - response - operationId: post-epm-install-pkgkey - description: '' - parameters: - - $ref: '#/paths/~1setup/post/parameters/0' - delete: - summary: EPM - Packages - Delete + - list + - page + - perPage + - total + operationId: get-fleet-enrollment-api-keys + parameters: [] + post: + summary: Enrollment API Key - Create tags: [] responses: '200': @@ -756,40 +679,24 @@ paths: schema: type: object properties: - response: - type: array - items: - type: object - properties: - id: - type: string - type: - type: string - required: - - id - - type - required: - - response - operationId: post-epm-delete-pkgkey + item: + $ref: '#/components/schemas/enrollment_api_key' + action: + type: string + enum: + - created + operationId: post-fleet-enrollment-api-keys parameters: - - $ref: '#/paths/~1setup/post/parameters/0' - requestBody: - content: - application/json: - schema: - type: object - properties: - force: - type: boolean - '/agents/{agentId}': + - $ref: '#/components/parameters/kbn_xsrf' + '/enrollment-api-keys/{keyId}': parameters: - schema: type: string - name: agentId + name: keyId in: path required: true get: - summary: Fleet - Agent - Info + summary: Enrollment API Key - Info tags: [] responses: '200': @@ -800,39 +707,33 @@ paths: type: object properties: item: - type: object + $ref: '#/components/schemas/enrollment_api_key' required: - item - operationId: get-fleet-agents-agentId - put: - summary: Fleet - Agent - Update - tags: [] - responses: {} - operationId: put-fleet-agents-agentId - parameters: - - $ref: '#/paths/~1setup/post/parameters/0' + operationId: get-fleet-enrollment-api-keys-keyId delete: - summary: Fleet - Agent - Delete + summary: Enrollment API Key - Delete tags: [] - responses: {} - operationId: delete-fleet-agents-agentId + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + action: + type: string + enum: + - deleted + required: + - action + operationId: delete-fleet-enrollment-api-keys-keyId parameters: - - $ref: '#/paths/~1setup/post/parameters/0' - '/install/{osType}': - parameters: - - schema: - type: string - name: osType - in: path - required: true - get: - summary: Fleet - Get OS install script - tags: [] - responses: {} - operationId: get-fleet-install-osType + - $ref: '#/components/parameters/kbn_xsrf' /package_policies: get: - summary: PackagePolicies - List + summary: Package policies - List tags: [] responses: '200': @@ -845,7 +746,7 @@ paths: items: type: array items: - $ref: '#/paths/~1package_policies~1%7BpackagePolicyId%7D/get/responses/200/content/application~1json/schema/properties/item' + $ref: '#/components/schemas/package_policy' total: type: number page: @@ -859,7 +760,7 @@ paths: parameters: [] parameters: [] post: - summary: PackagePolicies - Create + summary: Package policy - Create operationId: post-packagePolicies responses: '200': @@ -868,69 +769,12 @@ paths: content: application/json: schema: - title: NewPackagePolicy - type: object - description: '' - properties: - enabled: - type: boolean - package: - type: object - properties: - name: - type: string - version: - type: string - title: - type: string - required: - - name - - version - - title - namespace: - type: string - output_id: - type: string - inputs: - type: array - items: - type: object - properties: - type: - type: string - enabled: - type: boolean - processors: - type: array - items: - type: string - streams: - type: array - items: {} - config: - type: object - vars: - type: object - required: - - type - - enabled - - streams - policy_id: - type: string - name: - type: string - description: - type: string - required: - - output_id - - inputs - - policy_id - - name + $ref: '#/components/schemas/new_package_policy' parameters: - - $ref: '#/paths/~1setup/post/parameters/0' + - $ref: '#/components/parameters/kbn_xsrf' '/package_policies/{packagePolicyId}': get: - summary: PackagePolicies - Info + summary: Package policy - Info tags: [] responses: '200': @@ -941,21 +785,7 @@ paths: type: object properties: item: - title: PackagePolicy - allOf: - - type: object - properties: - id: - type: string - revision: - type: number - inputs: - type: array - items: {} - required: - - id - - revision - - $ref: '#/paths/~1package_policies/post/requestBody/content/application~1json/schema' + $ref: '#/components/schemas/package_policy' required: - item operationId: get-packagePolicies-packagePolicyId @@ -966,19 +796,13 @@ paths: in: path required: true put: - summary: PackagePolicies - Update + summary: Package policy - Update operationId: put-packagePolicies-packagePolicyId requestBody: content: application/json: schema: - title: UpdatePackagePolicy - allOf: - - type: object - properties: - version: - type: string - - $ref: '#/paths/~1package_policies/post/requestBody/content/application~1json/schema' + $ref: '#/components/schemas/update_package_policy' responses: '200': description: OK @@ -988,58 +812,477 @@ paths: type: object properties: item: - $ref: '#/paths/~1package_policies~1%7BpackagePolicyId%7D/get/responses/200/content/application~1json/schema/properties/item' + $ref: '#/components/schemas/package_policy' sucess: type: boolean required: - item - sucess parameters: - - $ref: '#/paths/~1setup/post/parameters/0' - /setup: - post: - summary: Ingest Manager - Setup - tags: [] - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - isInitialized: - type: boolean - '500': - description: Internal Server Error - content: - application/json: - schema: - type: object - properties: - message: - type: string - operationId: post-setup - parameters: - - schema: - type: string - in: header - name: kbn-xsrf - required: true + - $ref: '#/components/parameters/kbn_xsrf' components: securitySchemes: basicAuth: type: http scheme: basic - Enrollment API Key: + Enrollment_API_Key: name: Authorization type: apiKey in: header description: 'e.g. Authorization: ApiKey base64EnrollmentApiKey' - Access API Key: + Access_API_Key: name: Authorization type: apiKey in: header description: 'e.g. Authorization: ApiKey base64AccessApiKey' + parameters: + kbn_xsrf: + schema: + type: string + in: header + name: kbn-xsrf + required: true + page_size: + name: perPage + in: query + description: The number of items to return + required: false + schema: + type: integer + default: 50 + page_index: + name: page + in: query + required: false + schema: + type: integer + default: 1 + kuery: + name: kuery + in: query + required: false + schema: + type: string + schemas: + search_result: + title: SearchResult + type: object + properties: + description: + type: string + download: + type: string + icons: + type: string + name: + type: string + path: + type: string + title: + type: string + type: + type: string + version: + type: string + status: + type: string + savedObject: + type: object + required: + - description + - download + - icons + - name + - path + - title + - type + - version + - status + package_info: + title: PackageInfo + type: object + properties: + name: + type: string + title: + type: string + version: + type: string + readme: + type: string + description: + type: string + type: + type: string + categories: + type: array + items: + type: string + requirement: + oneOf: + - properties: + kibana: + type: object + properties: + versions: + type: string + - properties: + elasticsearch: + type: object + properties: + versions: + type: string + type: object + screenshots: + type: array + items: + type: object + properties: + src: + type: string + path: + type: string + title: + type: string + size: + type: string + type: + type: string + required: + - src + - path + icons: + type: array + items: + type: string + assets: + type: array + items: + type: string + internal: + type: boolean + format_version: + type: string + data_streams: + type: array + items: + type: object + properties: + title: + type: string + name: + type: string + release: + type: string + ingeset_pipeline: + type: string + vars: + type: array + items: + type: object + properties: + name: + type: string + default: + type: string + required: + - name + - default + type: + type: string + package: + type: string + required: + - title + - name + - release + - ingeset_pipeline + - type + - package + download: + type: string + path: + type: string + removable: + type: boolean + required: + - name + - title + - version + - description + - type + - categories + - requirement + - assets + - format_version + - download + - path + agent_type: + type: string + title: AgentType + enum: + - PERMANENT + - EPHEMERAL + - TEMPORARY + agent_metadata: + title: AgentMetadata + type: object + agent_status: + type: string + title: AgentStatus + enum: + - offline + - error + - online + - inactive + - warning + agent: + title: Agent + type: object + properties: + type: + $ref: '#/components/schemas/agent_type' + active: + type: boolean + enrolled_at: + type: string + unenrolled_at: + type: string + unenrollment_started_at: + type: string + shared_id: + type: string + deprecated: true + access_api_key_id: + type: string + default_api_key_id: + type: string + policy_id: + type: string + policy_revision: + type: number + last_checkin: + type: string + user_provided_metadata: + $ref: '#/components/schemas/agent_metadata' + local_metadata: + $ref: '#/components/schemas/agent_metadata' + id: + type: string + access_api_key: + type: string + status: + $ref: '#/components/schemas/agent_status' + default_api_key: + type: string + required: + - type + - active + - enrolled_at + - id + - status + bulk_upgrade_agents: + title: BulkUpgradeAgents + oneOf: + - type: object + properties: + version: + type: string + agents: + type: array + items: + type: string + required: + - version + - agents + - type: object + properties: + version: + type: string + source_uri: + type: string + agents: + type: array + items: + type: string + required: + - version + - agents + - type: object + properties: + version: + type: string + source_uri: + type: string + agents: + type: string + required: + - version + - agents + upgrade_agent: + title: UpgradeAgent + oneOf: + - type: object + properties: + version: + type: string + required: + - version + - type: object + properties: + version: + type: string + source_uri: + type: string + required: + - version + new_agent_policy: + title: NewAgentPolicy + type: object + properties: + name: + type: string + namespace: + type: string + description: + type: string + new_package_policy: + title: NewPackagePolicy + type: object + description: '' + properties: + enabled: + type: boolean + package: + type: object + properties: + name: + type: string + version: + type: string + title: + type: string + required: + - name + - version + - title + namespace: + type: string + output_id: + type: string + inputs: + type: array + items: + type: object + properties: + type: + type: string + enabled: + type: boolean + processors: + type: array + items: + type: string + streams: + type: array + items: {} + config: + type: object + vars: + type: object + required: + - type + - enabled + - streams + policy_id: + type: string + name: + type: string + description: + type: string + required: + - output_id + - inputs + - policy_id + - name + package_policy: + title: PackagePolicy + allOf: + - type: object + properties: + id: + type: string + revision: + type: number + inputs: + type: array + items: {} + required: + - id + - revision + - $ref: '#/components/schemas/new_package_policy' + agent_policy: + allOf: + - $ref: '#/components/schemas/new_agent_policy' + - type: object + properties: + id: + type: string + status: + type: string + enum: + - active + - inactive + packagePolicies: + oneOf: + - items: + type: string + - items: + $ref: '#/components/schemas/package_policy' + type: array + updated_on: + type: string + format: date-time + updated_by: + type: string + revision: + type: number + agents: + type: number + required: + - id + - status + enrollment_api_key: + title: EnrollmentApiKey + type: object + properties: + id: + type: string + api_key_id: + type: string + api_key: + type: string + name: + type: string + active: + type: boolean + policy_id: + type: string + created_at: + type: string + required: + - id + - api_key_id + - api_key + - active + - created_at + update_package_policy: + title: UpdatePackagePolicy + allOf: + - type: object + properties: + version: + type: string + - $ref: '#/components/schemas/new_package_policy' security: - basicAuth: [] diff --git a/x-pack/plugins/fleet/common/openapi/components/schemas/enrollment_api_key.yaml b/x-pack/plugins/fleet/common/openapi/components/schemas/enrollment_api_key.yaml index 3efe77b3bd606..e8491504d8416 100644 --- a/x-pack/plugins/fleet/common/openapi/components/schemas/enrollment_api_key.yaml +++ b/x-pack/plugins/fleet/common/openapi/components/schemas/enrollment_api_key.yaml @@ -1,3 +1,23 @@ -type: string title: EnrollmentApiKey -format: byte +type: object +properties: + id: + type: string + api_key_id: + type: string + api_key: + type: string + name: + type: string + active: + type: boolean + policy_id: + type: string + created_at: + type: string +required: + - id + - api_key_id + - api_key + - active + - created_at diff --git a/x-pack/plugins/fleet/common/openapi/entrypoint.yaml b/x-pack/plugins/fleet/common/openapi/entrypoint.yaml index 6ea8ae966bdca..0f7129a2a7cec 100644 --- a/x-pack/plugins/fleet/common/openapi/entrypoint.yaml +++ b/x-pack/plugins/fleet/common/openapi/entrypoint.yaml @@ -1,66 +1,70 @@ openapi: 3.0.0 +tags: [] info: - title: Ingest Manager + title: Fleet + description: OpenAPI schema for Fleet API endpoints version: '0.2' contact: - name: Ingest Team + name: Fleet Team license: - name: Elastic + name: Elastic License 2.0 + url: https://www.elastic.co/licensing/elastic-license servers: - url: 'http://localhost:5601/api/fleet' description: local paths: - /agent_policies: - $ref: paths/agent_policies.yaml - '/agent_policies/{agentPolicyId}': - $ref: 'paths/agent_policies@{agent_policy_id}.yaml' - '/agent_policies/{agentPolicyId}/copy': - $ref: 'paths/agent_policies@{agent_policy_id}@copy.yaml' - /agent_policies/delete: - $ref: paths/agent_policies@delete.yaml + # plugin-wide endpoint(s) + /setup: + $ref: paths/setup.yaml + # EPM / integrations endpoints + /epm/categories: + $ref: paths/epm@categories.yaml + /epm/packages: + $ref: paths/epm@packages.yaml + '/epm/packages/{pkgkey}': + $ref: 'paths/epm@packages@{pkgkey}.yaml' + # Agent-related endpoints + /agents/setup: + $ref: paths/agents@setup.yaml /agent-status: $ref: paths/agent_status.yaml /agents: $ref: paths/agents.yaml + /agents/bulk_upgrade: + $ref: paths/agents@bulk_upgrade.yaml + '/agents/{agentId}': + $ref: 'paths/agents@{agent_id}.yaml' '/agents/{agentId}/unenroll': $ref: 'paths/agents@{agent_id}@unenroll.yaml' '/agents/{agentId}/upgrade': $ref: 'paths/agents@{agent_id}@upgrade.yaml' - /agents/bulk_upgrade: - $ref: paths/agents@bulk_upgrade.yaml - /agents/setup: - $ref: paths/agents@setup.yaml + /agent_policies: + $ref: paths/agent_policies.yaml + '/agent_policies/{agentPolicyId}': + $ref: 'paths/agent_policies@{agent_policy_id}.yaml' + '/agent_policies/{agentPolicyId}/copy': + $ref: 'paths/agent_policies@{agent_policy_id}@copy.yaml' + /agent_policies/delete: + $ref: paths/agent_policies@delete.yaml /enrollment-api-keys: $ref: paths/enrollment_api_keys.yaml '/enrollment-api-keys/{keyId}': $ref: 'paths/enrollment_api_keys@{key_id}.yaml' - /epm/categories: - $ref: paths/epm@categories.yaml - /epm/packages: - $ref: paths/epm@packages.yaml - '/epm/packages/{pkgkey}': - $ref: 'paths/epm@packages@{pkgkey}.yaml' - '/agents/{agentId}': - $ref: 'paths/agents@{agent_id}.yaml' - '/install/{osType}': - $ref: 'paths/install@{os_type}.yaml' /package_policies: $ref: paths/package_policies.yaml '/package_policies/{packagePolicyId}': $ref: 'paths/package_policies@{package_policy_id}.yaml' - /setup: - $ref: paths/setup.yaml components: securitySchemes: basicAuth: type: http scheme: basic - Enrollment API Key: + Enrollment_API_Key: name: Authorization type: apiKey in: header description: 'e.g. Authorization: ApiKey base64EnrollmentApiKey' - Access API Key: + Access_API_Key: name: Authorization type: apiKey in: header diff --git a/x-pack/plugins/fleet/common/openapi/paths/agent_policies.yaml b/x-pack/plugins/fleet/common/openapi/paths/agent_policies.yaml index 2ba14fba7232b..9c17680b6c6bd 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/agent_policies.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/agent_policies.yaml @@ -1,5 +1,5 @@ get: - summary: Agent policy - List + summary: Agent policies - List tags: [] responses: '200': diff --git a/x-pack/plugins/fleet/common/openapi/paths/agent_status.yaml b/x-pack/plugins/fleet/common/openapi/paths/agent_status.yaml index 77ec9e85069a2..1b55cbd96733d 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/agent_status.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/agent_status.yaml @@ -1,7 +1,39 @@ get: - summary: Fleet - Agent - Status for policy + summary: Agents - Summary stats tags: [] - responses: {} + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + error: + type: integer + events: + type: integer + inactive: + type: integer + offline: + type: integer + online: + type: integer + other: + type: integer + total: + type: integer + updating: + type: integer + required: + - error + - events + - inactive + - offline + - online + - other + - total + - updating operationId: get-fleet-agent-status parameters: - schema: diff --git a/x-pack/plugins/fleet/common/openapi/paths/agents.yaml b/x-pack/plugins/fleet/common/openapi/paths/agents.yaml index e5039bc2caccf..bb3905eab7c0e 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/agents.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/agents.yaml @@ -1,5 +1,5 @@ get: - summary: Fleet - Agent - List + summary: Agents - List tags: [] responses: '200': @@ -12,7 +12,7 @@ get: list: type: array items: - type: object + $ref: ../components/schemas/agent.yaml total: type: number page: diff --git a/x-pack/plugins/fleet/common/openapi/paths/agents@bulk_upgrade.yaml b/x-pack/plugins/fleet/common/openapi/paths/agents@bulk_upgrade.yaml index 2092fbf000ab8..37c7ad31c5b01 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/agents@bulk_upgrade.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/agents@bulk_upgrade.yaml @@ -1,5 +1,5 @@ post: - summary: Fleet - Agent - Bulk Upgrade + summary: Agents - Bulk Upgrade tags: [] responses: '200': diff --git a/x-pack/plugins/fleet/common/openapi/paths/agents@{agent_id}.yaml b/x-pack/plugins/fleet/common/openapi/paths/agents@{agent_id}.yaml index e65c80d8fae88..a898b9b563f17 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/agents@{agent_id}.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/agents@{agent_id}.yaml @@ -5,7 +5,7 @@ parameters: in: path required: true get: - summary: Fleet - Agent - Info + summary: Agent - Info tags: [] responses: '200': @@ -16,21 +16,45 @@ get: type: object properties: item: - type: object + $ref: ../components/schemas/agent.yaml required: - item operationId: get-fleet-agents-agentId put: - summary: Fleet - Agent - Update + summary: Agent - Update tags: [] - responses: {} + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + item: + $ref: ../components/schemas/agent.yaml + required: + - item operationId: put-fleet-agents-agentId parameters: - $ref: ../components/headers/kbn_xsrf.yaml delete: - summary: Fleet - Agent - Delete + summary: Agent - Delete tags: [] - responses: {} + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + action: + type: string + enum: + - deleted + required: + - action operationId: delete-fleet-agents-agentId parameters: - $ref: ../components/headers/kbn_xsrf.yaml diff --git a/x-pack/plugins/fleet/common/openapi/paths/agents@{agent_id}@unenroll.yaml b/x-pack/plugins/fleet/common/openapi/paths/agents@{agent_id}@unenroll.yaml index eccbbbfc9b8ca..5b848b715080b 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/agents@{agent_id}@unenroll.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/agents@{agent_id}@unenroll.yaml @@ -5,9 +5,30 @@ parameters: in: path required: true post: - summary: Fleet - Agent - Unenroll + summary: Agent - Unenroll tags: [] - responses: {} + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + '400': + description: BAD REQUEST + content: + application/json: + schema: + type: object + properties: + error: + type: string + message: + type: string + statusCode: + type: number + enum: + - 400 operationId: post-fleet-agents-unenroll parameters: - $ref: ../components/headers/kbn_xsrf.yaml diff --git a/x-pack/plugins/fleet/common/openapi/paths/agents@{agent_id}@upgrade.yaml b/x-pack/plugins/fleet/common/openapi/paths/agents@{agent_id}@upgrade.yaml index ce871cac0d068..14a0598ce6ecb 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/agents@{agent_id}@upgrade.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/agents@{agent_id}@upgrade.yaml @@ -5,7 +5,7 @@ parameters: in: path required: true post: - summary: Fleet - Agent - Upgrade + summary: Agent - Upgrade tags: [] responses: '200': diff --git a/x-pack/plugins/fleet/common/openapi/paths/enrollment_api_keys.yaml b/x-pack/plugins/fleet/common/openapi/paths/enrollment_api_keys.yaml index 22d27c0596d68..f00c46e7683e5 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/enrollment_api_keys.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/enrollment_api_keys.yaml @@ -1,13 +1,48 @@ get: - summary: Enrollment - List + summary: Enrollment API Keys - List tags: [] - responses: {} + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + list: + type: array + items: + $ref: ../components/schemas/enrollment_api_key.yaml + page: + type: number + perPage: + type: number + total: + type: number + required: + - list + - page + - perPage + - total operationId: get-fleet-enrollment-api-keys parameters: [] post: - summary: Enrollment - Create + summary: Enrollment API Key - Create tags: [] - responses: {} + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + item: + $ref: ../components/schemas/enrollment_api_key.yaml + action: + type: string + enum: + - created operationId: post-fleet-enrollment-api-keys parameters: - $ref: ../components/headers/kbn_xsrf.yaml diff --git a/x-pack/plugins/fleet/common/openapi/paths/enrollment_api_keys@{key_id}.yaml b/x-pack/plugins/fleet/common/openapi/paths/enrollment_api_keys@{key_id}.yaml index 3b43950427e82..021f6582641ed 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/enrollment_api_keys@{key_id}.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/enrollment_api_keys@{key_id}.yaml @@ -5,14 +5,38 @@ parameters: in: path required: true get: - summary: Enrollment - Info + summary: Enrollment API Key - Info tags: [] - responses: {} + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + item: + $ref: ../components/schemas/enrollment_api_key.yaml + required: + - item operationId: get-fleet-enrollment-api-keys-keyId delete: - summary: Enrollment - Delete + summary: Enrollment API Key - Delete tags: [] - responses: {} + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + action: + type: string + enum: + - deleted + required: + - action operationId: delete-fleet-enrollment-api-keys-keyId parameters: - $ref: ../components/headers/kbn_xsrf.yaml diff --git a/x-pack/plugins/fleet/common/openapi/paths/epm@categories.yaml b/x-pack/plugins/fleet/common/openapi/paths/epm@categories.yaml index 0fc26a4e5c826..567d621a2e21d 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/epm@categories.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/epm@categories.yaml @@ -1,5 +1,5 @@ get: - summary: EPM - Categories + summary: Packages - Categories tags: [] responses: '200': diff --git a/x-pack/plugins/fleet/common/openapi/paths/epm@packages.yaml b/x-pack/plugins/fleet/common/openapi/paths/epm@packages.yaml index afbe8ee2dc321..fe79a9a4186b2 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/epm@packages.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/epm@packages.yaml @@ -1,5 +1,5 @@ get: - summary: EPM - Packages - List + summary: Packages - List tags: [] responses: '200': diff --git a/x-pack/plugins/fleet/common/openapi/paths/epm@packages@{pkgkey}.yaml b/x-pack/plugins/fleet/common/openapi/paths/epm@packages@{pkgkey}.yaml index 85d8615a9eb4b..2c4567bd36ba1 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/epm@packages@{pkgkey}.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/epm@packages@{pkgkey}.yaml @@ -1,5 +1,5 @@ get: - summary: EPM - Packages - Info + summary: Packages - Info tags: [] responses: '200': @@ -33,7 +33,7 @@ parameters: in: path required: true post: - summary: EPM - Packages - Install + summary: Packages - Install tags: [] responses: '200': @@ -62,7 +62,7 @@ post: parameters: - $ref: ../components/headers/kbn_xsrf.yaml delete: - summary: EPM - Packages - Delete + summary: Packages - Delete tags: [] responses: '200': diff --git a/x-pack/plugins/fleet/common/openapi/paths/install@{os_type}.yaml b/x-pack/plugins/fleet/common/openapi/paths/install@{os_type}.yaml deleted file mode 100644 index 80351aa7ae119..0000000000000 --- a/x-pack/plugins/fleet/common/openapi/paths/install@{os_type}.yaml +++ /dev/null @@ -1,11 +0,0 @@ -parameters: - - schema: - type: string - name: osType - in: path - required: true -get: - summary: Fleet - Get OS install script - tags: [] - responses: {} - operationId: get-fleet-install-osType diff --git a/x-pack/plugins/fleet/common/openapi/paths/package_policies.yaml b/x-pack/plugins/fleet/common/openapi/paths/package_policies.yaml index 47eca50f0524b..24b3e091f1bc2 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/package_policies.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/package_policies.yaml @@ -1,5 +1,5 @@ get: - summary: PackagePolicies - List + summary: Package policies - List tags: [] responses: '200': @@ -26,7 +26,7 @@ get: parameters: [] parameters: [] post: - summary: PackagePolicies - Create + summary: Package policy - Create operationId: post-packagePolicies responses: '200': diff --git a/x-pack/plugins/fleet/common/openapi/paths/package_policies@{package_policy_id}.yaml b/x-pack/plugins/fleet/common/openapi/paths/package_policies@{package_policy_id}.yaml index 4e0315556b614..9a8a1477fea78 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/package_policies@{package_policy_id}.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/package_policies@{package_policy_id}.yaml @@ -1,5 +1,5 @@ get: - summary: PackagePolicies - Info + summary: Package policy - Info tags: [] responses: '200': @@ -21,7 +21,7 @@ parameters: in: path required: true put: - summary: PackagePolicies - Update + summary: Package policy - Update operationId: put-packagePolicies-packagePolicyId requestBody: content: diff --git a/x-pack/plugins/fleet/common/openapi/paths/setup.yaml b/x-pack/plugins/fleet/common/openapi/paths/setup.yaml index 62ad2cb66dacb..a157dea8b38dc 100644 --- a/x-pack/plugins/fleet/common/openapi/paths/setup.yaml +++ b/x-pack/plugins/fleet/common/openapi/paths/setup.yaml @@ -1,5 +1,5 @@ post: - summary: Ingest Manager - Setup + summary: Setup tags: [] responses: '200': diff --git a/x-pack/plugins/fleet/common/types/models/epm.ts b/x-pack/plugins/fleet/common/types/models/epm.ts index 36554b8409364..bbb571f963dc9 100644 --- a/x-pack/plugins/fleet/common/types/models/epm.ts +++ b/x-pack/plugins/fleet/common/types/models/epm.ts @@ -414,7 +414,7 @@ export interface IndexTemplateMappings { // This is an index template v2, see https://github.com/elastic/elasticsearch/issues/53101 // until "proper" documentation of the new format is available. -// Ingest Manager does not use nor support the legacy index template v1 format at all +// Fleet does not use nor support the legacy index template v1 format at all export interface IndexTemplate { priority: number; index_patterns: string[]; diff --git a/x-pack/plugins/fleet/common/types/rest_spec/index.ts b/x-pack/plugins/fleet/common/types/rest_spec/index.ts index dfbf5b968f3c7..870cf3f3f1b82 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/index.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/index.ts @@ -13,7 +13,6 @@ export * from './agent_policy'; export * from './fleet_setup'; export * from './epm'; export * from './enrollment_api_key'; -export * from './install_script'; export * from './ingest_setup'; export * from './output'; export * from './settings'; diff --git a/x-pack/plugins/fleet/common/types/rest_spec/install_script.ts b/x-pack/plugins/fleet/common/types/rest_spec/install_script.ts deleted file mode 100644 index 4a43405e4e3ba..0000000000000 --- a/x-pack/plugins/fleet/common/types/rest_spec/install_script.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export interface InstallScriptRequest { - params: { - osType: 'macos'; - }; -} diff --git a/x-pack/plugins/fleet/server/services/install_script/index.ts b/x-pack/plugins/fleet/server/services/install_script/index.ts deleted file mode 100644 index b978eddbfc673..0000000000000 --- a/x-pack/plugins/fleet/server/services/install_script/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { appContextService } from '../app_context'; - -import { macosInstallTemplate } from './install_templates/macos'; -import { linuxInstallTemplate } from './install_templates/linux'; - -export function getScript(osType: 'macos' | 'linux', kibanaUrl: string): string { - const variables = { kibanaUrl, kibanaVersion: appContextService.getKibanaVersion() }; - - switch (osType) { - case 'macos': - return macosInstallTemplate(variables); - case 'linux': - return linuxInstallTemplate(variables); - default: - throw new Error(`${osType} is not supported.`); - } -} diff --git a/x-pack/plugins/fleet/server/services/install_script/install_templates/linux.ts b/x-pack/plugins/fleet/server/services/install_script/install_templates/linux.ts deleted file mode 100644 index 4e31193efc0e6..0000000000000 --- a/x-pack/plugins/fleet/server/services/install_script/install_templates/linux.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { InstallTemplateFunction } from './types'; - -export const linuxInstallTemplate: InstallTemplateFunction = (variables) => { - const artifact = `elastic-agent-${variables.kibanaVersion}-linux-x86_64`; - - return `#!/bin/sh - -set -e -curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/${artifact}.tar.gz -tar -xzvf ${artifact}.tar.gz -cd ${artifact} -./elastic-agent enroll ${variables.kibanaUrl} $API_KEY --force -./elastic-agent run -`; -}; diff --git a/x-pack/plugins/fleet/server/services/install_script/install_templates/macos.ts b/x-pack/plugins/fleet/server/services/install_script/install_templates/macos.ts deleted file mode 100644 index abe52f64d0e5c..0000000000000 --- a/x-pack/plugins/fleet/server/services/install_script/install_templates/macos.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { InstallTemplateFunction } from './types'; - -export const macosInstallTemplate: InstallTemplateFunction = (variables) => { - const artifact = `elastic-agent-${variables.kibanaVersion}-darwin-x86_64`; - - return `#!/bin/sh - -set -e -curl -L -O https://artifacts.elastic.co/downloads/beats/elastic-agent/${artifact}.tar.gz -tar -xzvf ${artifact}.tar.gz -cd ${artifact} -./elastic-agent enroll ${variables.kibanaUrl} $API_KEY --force -./elastic-agent run -`; -}; diff --git a/x-pack/plugins/fleet/server/services/install_script/install_templates/types.ts b/x-pack/plugins/fleet/server/services/install_script/install_templates/types.ts deleted file mode 100644 index e8fa001f7eb65..0000000000000 --- a/x-pack/plugins/fleet/server/services/install_script/install_templates/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export type InstallTemplateFunction = (variables: { - kibanaUrl: string; - kibanaVersion: string; -}) => string; diff --git a/x-pack/plugins/fleet/server/types/rest_spec/index.ts b/x-pack/plugins/fleet/server/types/rest_spec/index.ts index c4fbb05ffd42f..badf02e2e6242 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/index.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/index.ts @@ -11,7 +11,6 @@ export * from './agent'; export * from './package_policy'; export * from './epm'; export * from './enrollment_api_key'; -export * from './install_script'; export * from './output'; export * from './preconfiguration'; export * from './settings'; diff --git a/x-pack/plugins/fleet/server/types/rest_spec/install_script.ts b/x-pack/plugins/fleet/server/types/rest_spec/install_script.ts deleted file mode 100644 index 05ddfeb6f7c04..0000000000000 --- a/x-pack/plugins/fleet/server/types/rest_spec/install_script.ts +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; - -export const InstallScriptRequestSchema = { - params: schema.object({ - osType: schema.oneOf([schema.literal('macos'), schema.literal('linux')]), - }), -}; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/filter_bar.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/filter_bar.tsx index 7cb75e488583a..f29f87191bc13 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/filter_bar.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/filter_bar.tsx @@ -12,12 +12,7 @@ import { WaffleTimeControls } from './waffle/waffle_time_controls'; import { SearchBar } from './search_bar'; export const FilterBar = () => ( - + diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx index 2e79e7e4ab8c4..833b532a943d1 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/layout.tsx @@ -152,7 +152,7 @@ export const Layout = React.memo( gutterSize="m" > - + diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/interval_label.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/interval_label.tsx index cae437aab4cf8..895c061cdd24b 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/interval_label.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/interval_label.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiText } from '@elastic/eui'; +import { EuiIconTip } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; interface Props { @@ -19,14 +19,16 @@ export const IntervalLabel = ({ intervalAsString }: Props) => { } return ( - -

+ -

-
+ } + /> ); }; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_time_controls.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_time_controls.tsx index c9b5711dd2cd8..765ae9d131ba6 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_time_controls.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/waffle_time_controls.tsx @@ -53,7 +53,7 @@ export const WaffleTimeControls = withTheme(({ theme }: Props) => { ); return ( - + { + if (activeData) { + const datatables = Object.values(activeData); + const formulaDetected = datatables.some((datatable) => { + return tableHasFormulas(datatable.columns, datatable.rows); + }); + if (formulaDetected) { + return i18n.translate('xpack.lens.app.downloadButtonFormulasWarning', { + defaultMessage: + 'Your CSV contains characters which spreadsheet applications can interpret as formulas', + }); + } + } + return undefined; + }, + }, actions: { exportToCSV: () => { if (!activeData) { @@ -230,6 +256,7 @@ export const LensTopNavMenu = ({ csvSeparator: uiSettings.get('csv:separator', ','), quoteValues: uiSettings.get('csv:quoteValues', true), formatFactory: data.fieldFormats.deserialize, + escapeFormulaValues: false, }), type: exporters.CSV_MIME_TYPE, }; diff --git a/x-pack/plugins/lens/public/app_plugin/types.ts b/x-pack/plugins/lens/public/app_plugin/types.ts index 7f1c21fa5a9bd..499ba3c86bca5 100644 --- a/x-pack/plugins/lens/public/app_plugin/types.ts +++ b/x-pack/plugins/lens/public/app_plugin/types.ts @@ -114,6 +114,10 @@ export interface LensAppServices { dashboardFeatureFlag: DashboardFeatureFlagConfig; } +export interface LensTopNavTooltips { + showExportWarning: () => string | undefined; +} + export interface LensTopNavActions { saveAndReturn: () => void; showSaveModal: () => void; diff --git a/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.tsx b/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.tsx index 218e3cfd61abb..705484edcf0e6 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/components/dimension_editor.tsx @@ -84,7 +84,7 @@ export function TableDimensionEditor( onChange: onSummaryLabelChangeToDebounce, value: column?.summaryLabel, }, - { allowEmptyString: true } // empty string is a valid label for this feature + { allowFalsyValue: true } // falsy values are valid for this feature ); if (!column) return null; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/overall_metric.test.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/overall_metric.test.ts new file mode 100644 index 0000000000000..5277e09189b0d --- /dev/null +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/overall_metric.test.ts @@ -0,0 +1,50 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createMockedIndexPattern } from '../../../mocks'; +import type { IndexPatternLayer } from '../../../types'; +import { + overallAverageOperation, + overallMaxOperation, + overallMinOperation, + overallSumOperation, +} from '../index'; + +describe('overall_metric', () => { + const indexPattern = createMockedIndexPattern(); + let layer: IndexPatternLayer; + + beforeEach(() => { + layer = { + indexPatternId: '1', + columnOrder: [], + columns: {}, + }; + }); + + describe('buildColumn', () => { + it('should assign the right operationType', () => { + const args = { + layer, + indexPattern, + referenceIds: ['a'], + }; + expect(overallAverageOperation.buildColumn(args)).toEqual( + expect.objectContaining({ operationType: 'overall_average' }) + ); + expect(overallMaxOperation.buildColumn(args)).toEqual( + expect.objectContaining({ operationType: 'overall_max' }) + ); + expect(overallMinOperation.buildColumn(args)).toEqual( + expect.objectContaining({ operationType: 'overall_min' }) + ); + expect(overallSumOperation.buildColumn(args)).toEqual( + expect.objectContaining({ operationType: 'overall_sum' }) + ); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/overall_metric.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/overall_metric.tsx index 4250811e11452..96f6c995e23c8 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/overall_metric.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/overall_metric.tsx @@ -6,9 +6,12 @@ */ import { i18n } from '@kbn/i18n'; -import { FormattedIndexPatternColumn, ReferenceBasedIndexPatternColumn } from '../column_types'; +import type { + FormattedIndexPatternColumn, + ReferenceBasedIndexPatternColumn, +} from '../column_types'; import { optionallHistogramBasedOperationToExpression } from './utils'; -import { OperationDefinition } from '..'; +import type { OperationDefinition } from '..'; import { getFormatFromPreviousColumn } from '../helpers'; type OverallMetricIndexPatternColumn = FormattedIndexPatternColumn & @@ -75,7 +78,7 @@ function buildOverallMetricOperation + setValue={(value) => { setState({ ...state, layers: [{ ...layer, percentDecimals: value }], - }) - } + }); + }} /> @@ -232,7 +232,13 @@ const DecimalPlaceSlider = ({ value: number; setValue: (value: number) => void; }) => { - const { inputValue, handleInputChange } = useDebouncedValue({ value, onChange: setValue }); + const { inputValue, handleInputChange } = useDebouncedValue( + { + value, + onChange: setValue, + }, + { allowFalsyValue: true } + ); return ( { it('should allow empty input to be updated', () => { const onChangeMock = jest.fn(); const { result } = renderHook(() => - useDebouncedValue({ value: 'a', onChange: onChangeMock }, { allowEmptyString: true }) + useDebouncedValue({ value: 'a', onChange: onChangeMock }, { allowFalsyValue: true }) ); act(() => { diff --git a/x-pack/plugins/lens/public/shared_components/debounced_value.ts b/x-pack/plugins/lens/public/shared_components/debounced_value.ts index 54696e672ccbb..fa8fc22dedd57 100644 --- a/x-pack/plugins/lens/public/shared_components/debounced_value.ts +++ b/x-pack/plugins/lens/public/shared_components/debounced_value.ts @@ -21,11 +21,11 @@ export const useDebouncedValue = ( onChange: (val: T) => void; value: T; }, - { allowEmptyString }: { allowEmptyString?: boolean } = {} + { allowFalsyValue }: { allowFalsyValue?: boolean } = {} ) => { const [inputValue, setInputValue] = useState(value); const unflushedChanges = useRef(false); - const shouldUpdateWithEmptyString = Boolean(allowEmptyString); + const shouldUpdateWithFalsyValue = Boolean(allowFalsyValue); // Save the initial value const initialValue = useRef(value); @@ -57,7 +57,7 @@ export const useDebouncedValue = ( const handleInputChange = (val: T) => { setInputValue(val); - const valueToUpload = shouldUpdateWithEmptyString + const valueToUpload = shouldUpdateWithFalsyValue ? val ?? initialValue.current : val || initialValue.current; onChangeDebounced(valueToUpload); diff --git a/x-pack/plugins/ml/public/application/components/annotations/annotation_description_list/__snapshots__/index.test.tsx.snap b/x-pack/plugins/ml/public/application/components/annotations/annotation_description_list/__snapshots__/index.test.tsx.snap index 55513c3db060a..275b46d154ed6 100644 --- a/x-pack/plugins/ml/public/application/components/annotations/annotation_description_list/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/ml/public/application/components/annotations/annotation_description_list/__snapshots__/index.test.tsx.snap @@ -3,6 +3,7 @@ exports[`AnnotationDescriptionList Initialization with annotation. 1`] = ` { ); - const updateBtn = getByTestId('annotationFlyoutUpdateButton'); + const updateBtn = getByTestId('annotationFlyoutUpdateOrCreateButton'); expect(updateBtn).toBeDisabled(); }); @@ -79,7 +79,7 @@ describe('AnnotationFlyout', () => { ); - const updateBtn = getByTestId('annotationFlyoutUpdateButton'); + const updateBtn = getByTestId('annotationFlyoutUpdateOrCreateButton'); expect(updateBtn).toBeDisabled(); await waitFor(() => { const errorText = screen.queryByText(/characters above maximum length/); @@ -97,7 +97,7 @@ describe('AnnotationFlyout', () => { ); - const updateBtn = getByTestId('annotationFlyoutUpdateButton'); + const updateBtn = getByTestId('annotationFlyoutUpdateOrCreateButton'); expect(updateBtn).not.toBeDisabled(); expect(screen.queryByTestId('mlAnnotationFlyout')).toBeInTheDocument(); diff --git a/x-pack/plugins/ml/public/application/components/annotations/annotation_flyout/index.tsx b/x-pack/plugins/ml/public/application/components/annotations/annotation_flyout/index.tsx index 3d3200faf8095..812cba95b5d93 100644 --- a/x-pack/plugins/ml/public/application/components/annotations/annotation_flyout/index.tsx +++ b/x-pack/plugins/ml/public/application/components/annotations/annotation_flyout/index.tsx @@ -343,6 +343,7 @@ export class AnnotationFlyoutUI extends Component { onChange={this.annotationTextChangeHandler} placeholder="..." value={annotationState.annotation} + data-test-subj={'mlAnnotationsFlyoutTextInput'} /> @@ -360,13 +361,18 @@ export class AnnotationFlyoutUI extends Component { applyAnnotationToSeries: !this.state.applyAnnotationToSeries, }) } + data-test-subj={'mlAnnotationsFlyoutApplyToSeriesButton'} /> - + { {isExistingAnnotation && ( - + { fill isDisabled={isInvalid === true} onClick={this.saveOrUpdateAnnotation} - data-test-subj={'annotationFlyoutUpdateButton'} + data-test-subj={'annotationFlyoutUpdateOrCreateButton'} > {isExistingAnnotation ? ( = (props) => { className={'mlAnnotationFlyout'} > - +

{isExistingAnnotation ? ( { return {key}; }, + 'data-test-subj': `mlAnnotationsColumnLabel`, }); } @@ -486,6 +494,7 @@ class AnnotationsTableUI extends Component { annotationUpdatesService.setValue(originalAnnotation ?? annotation); }, + 'data-test-subj': `mlAnnotationsActionEdit`, }); if (this.state.jobId && this.props.jobs[0].analysis_config.bucket_span) { @@ -501,6 +510,7 @@ class AnnotationsTableUI extends Component { datafeedEnd: annotation.end_timestamp, }); }, + 'data-test-subj': `mlAnnotationsActionViewDatafeed`, }); } @@ -549,11 +559,13 @@ class AnnotationsTableUI extends Component { icon: 'visLine', type: 'icon', onClick: (annotation) => this.openSingleMetricView(annotation), + 'data-test-subj': `mlAnnotationsActionOpenInSingleMetricViewer`, }); } const getRowProps = (item) => { return { + 'data-test-subj': `mlAnnotationsTableRow row-${item._id}`, onMouseOver: () => this.onMouseOverRow(item), onMouseLeave: () => this.onMouseLeaveRow(), }; @@ -594,6 +606,7 @@ class AnnotationsTableUI extends Component { name: field.key, view: `${field.key} (${field.doc_count})`, })), + 'data-test-subj': 'mlAnnotationTableEventFilter', }, ]; @@ -692,6 +705,7 @@ class AnnotationsTableUI extends Component { defaultMessage: 'Actions', }), actions, + 'data-test-subj': `mlAnnotationsColumnActions`, }, { // hidden column, for search only @@ -707,6 +721,7 @@ class AnnotationsTableUI extends Component { return ( = ({ buttonColor="danger" defaultFocusedButton={EUI_MODAL_CONFIRM_BUTTON} className="eui-textBreakWord" + data-test-subj={'mlAnnotationFlyoutConfirmDeleteModal'} /> )} diff --git a/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx b/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx index d20042ddd9443..6091ab22692af 100644 --- a/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx +++ b/x-pack/plugins/ml/public/application/explorer/anomaly_timeline.tsx @@ -38,6 +38,9 @@ import { NoOverallData } from './components/no_overall_data'; import { SeverityControl } from '../components/severity_control'; import { AnomalyTimelineHelpPopover } from './anomaly_timeline_help_popover'; import { isDefined } from '../../../common/types/guards'; +import { MlTooltipComponent } from '../components/chart_tooltip'; +import { SwimlaneAnnotationContainer } from './swimlane_annotation_container'; +import { AnomalyTimelineService } from '../services/anomaly_timeline_service'; function mapSwimlaneOptionsToEuiOptions(options: string[]) { return options.map((option) => ({ @@ -92,6 +95,7 @@ export const AnomalyTimeline: FC = React.memo( swimLaneSeverity, overallSwimlaneData, viewBySwimlaneData, + swimlaneContainerWidth, } = explorerState; const [severityUpdate, setSeverityUpdate] = useState(swimLaneSeverity); @@ -140,6 +144,18 @@ export const AnomalyTimeline: FC = React.memo( }; }, [selectedCells]); + const annotationXDomain = useMemo( + () => + AnomalyTimelineService.isOverallSwimlaneData(overallSwimlaneData) + ? { + min: overallSwimlaneData.earliest * 1000, + max: overallSwimlaneData.latest * 1000, + minInterval: overallSwimlaneData.interval * 1000, + } + : undefined, + [overallSwimlaneData] + ); + return ( <> @@ -259,6 +275,21 @@ export const AnomalyTimeline: FC = React.memo( + {annotationXDomain && Array.isArray(annotations) && annotations.length > 0 ? ( + <> + + {(tooltipService) => ( + + )} + + + + ) : null} = React.memo( /> - {viewBySwimlaneOptions.length > 0 && ( +

= const dimensions = canvasRef.current.getBoundingClientRect(); const startingXPos = Y_AXIS_LABEL_WIDTH + 2 * Y_AXIS_LABEL_PADDING; - const endingXPos = dimensions.width - 2 * Y_AXIS_LABEL_PADDING - 4; + const endingXPos = dimensions.width - X_AXIS_RIGHT_OVERFLOW; const svg = chartElement .append('svg') @@ -82,18 +83,23 @@ export const SwimlaneAnnotationContainer: FC = // Add annotation marker annotationsData.forEach((d) => { - const annotationWidth = d.end_timestamp - ? xScale(Math.min(d.end_timestamp, domain.max)) - - Math.max(xScale(d.timestamp), startingXPos) - : 0; - + const annotationWidth = Math.max( + d.end_timestamp + ? xScale(Math.min(d.end_timestamp, domain.max)) - + Math.max(xScale(d.timestamp), startingXPos) + : 0, + ANNOTATION_MIN_WIDTH + ); + + const xPos = d.timestamp >= domain.min ? xScale(d.timestamp) : startingXPos; svg .append('rect') .classed('mlAnnotationRect', true) - .attr('x', d.timestamp >= domain.min ? xScale(d.timestamp) : startingXPos) + // If annotation is at the end, prevent overflow by shifting it back + .attr('x', xPos + annotationWidth >= endingXPos ? endingXPos - annotationWidth : xPos) .attr('y', 0) .attr('height', ANNOTATION_CONTAINER_HEIGHT) - .attr('width', Math.max(annotationWidth, ANNOTATION_MIN_WIDTH)) + .attr('width', annotationWidth) .on('mouseover', function () { const startingTime = formatHumanReadableDateTimeSeconds(d.timestamp); const endingTime = diff --git a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx index 86ec2014c8339..c58ced33b277d 100644 --- a/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx +++ b/x-pack/plugins/ml/public/application/explorer/swimlane_container.tsx @@ -38,17 +38,17 @@ import { ANOMALY_THRESHOLD, SEVERITY_COLORS } from '../../../common'; import { TimeBuckets as TimeBucketsClass } from '../util/time_buckets'; import { SWIMLANE_TYPE, SwimlaneType } from './explorer_constants'; import { mlEscape } from '../util/string_utils'; -import { FormattedTooltip, MlTooltipComponent } from '../components/chart_tooltip/chart_tooltip'; +import { FormattedTooltip } from '../components/chart_tooltip/chart_tooltip'; import { formatHumanReadableDateTime } from '../../../common/util/date_utils'; import './_explorer.scss'; import { EMPTY_FIELD_VALUE_LABEL } from '../timeseriesexplorer/components/entity_control/entity_control'; import { useUiSettings } from '../contexts/kibana'; import { - SwimlaneAnnotationContainer, Y_AXIS_LABEL_WIDTH, Y_AXIS_LABEL_PADDING, Y_AXIS_LABEL_FONT_COLOR, + X_AXIS_RIGHT_OVERFLOW, } from './swimlane_annotation_container'; import { AnnotationsTable } from '../../../common/types/annotations'; @@ -333,6 +333,8 @@ export const SwimlaneContainer: FC = ({ return moment(v).format(scaledDateFormat); }, fontSize: 12, + // Required to calculate where the swimlane ends + width: X_AXIS_RIGHT_OVERFLOW * 2, }, brushMask: { fill: isDarkTheme ? 'rgb(30,31,35,80%)' : 'rgb(247,247,247,50%)', @@ -480,21 +482,6 @@ export const SwimlaneContainer: FC = ({ )} - {swimlaneType === SWIMLANE_TYPE.OVERALL && - showSwimlane && - xDomain !== undefined && - !isLoading && ( - - {(tooltipService) => ( - - )} - - )} diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/rare_detector/detector_cards.tsx b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/rare_detector/detector_cards.tsx index 8da41b0e7c875..b78970eca59d1 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/rare_detector/detector_cards.tsx +++ b/x-pack/plugins/ml/public/application/jobs/new_job/pages/components/pick_fields_step/components/rare_detector/detector_cards.tsx @@ -29,7 +29,7 @@ export const RareCard: FC = ({ onClick, isSelected }) => ( <> } @@ -52,7 +52,7 @@ export const RareInPopulationCard: FC = ({ onClick, isSelected }) => <> } @@ -75,7 +75,7 @@ export const FrequentlyRareInPopulationCard: FC = ({ onClick, isSelec <> } diff --git a/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx b/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx index f645a0753f8c2..42927d9b4ef50 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/explorer.tsx @@ -108,6 +108,7 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim setGlobalState('time', { from: start, to: end, + ...(start === 'now' || end === 'now' ? { ts: Date.now() } : {}), }); } } @@ -127,7 +128,7 @@ const ExplorerUrlStateManager: FC = ({ jobsWithTim to: globalState.time.to, }); } - }, [lastRefresh, globalState?.time?.from, globalState?.time?.to]); + }, [globalState?.time?.from, globalState?.time?.to, globalState?.time?.ts]); const getJobsWithStoppedPartitions = useCallback(async (selectedJobIds: string[]) => { try { diff --git a/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer.tsx b/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer.tsx index 6eb4386276753..541449a9c7530 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/timeseriesexplorer.tsx @@ -118,6 +118,7 @@ export const TimeSeriesExplorerUrlStateManager: FC { const start = Math.max(this.contextXScale(moment(d.timestamp)) + 1, contextXRangeStart); - const end = + const end = Math.min( + contextXRangeEnd, typeof d.end_timestamp !== 'undefined' ? this.contextXScale(moment(d.end_timestamp)) - 1 - : start + ANNOTATION_MIN_WIDTH; + : start + ANNOTATION_MIN_WIDTH + ); const width = Math.max(ANNOTATION_MIN_WIDTH, end - start); return width; }); diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js index b6b63d7713b85..a92d29baf93c1 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/timeseriesexplorer.js @@ -1231,7 +1231,7 @@ export class TimeSeriesExplorer extends React.Component { )} {focusAnnotationData && focusAnnotationData.length > 0 && (

diff --git a/x-pack/plugins/observability/public/components/app/resources/index.tsx b/x-pack/plugins/observability/public/components/app/resources/index.tsx index dd1df9b7ccd8c..1a0c473734993 100644 --- a/x-pack/plugins/observability/public/components/app/resources/index.tsx +++ b/x-pack/plugins/observability/public/components/app/resources/index.tsx @@ -45,7 +45,7 @@ export function Resources() {

- + ); } diff --git a/x-pack/plugins/observability/public/components/app/section/alerts/index.tsx b/x-pack/plugins/observability/public/components/app/section/alerts/index.tsx index 0adb9ceb6e9f8..44f699c6c390b 100644 --- a/x-pack/plugins/observability/public/components/app/section/alerts/index.tsx +++ b/x-pack/plugins/observability/public/components/app/section/alerts/index.tsx @@ -14,6 +14,8 @@ import { EuiLink, EuiText, EuiSpacer, + EuiTitle, + EuiButton, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import moment from 'moment'; @@ -22,7 +24,6 @@ import { EuiSelect } from '@elastic/eui'; import { uniqBy } from 'lodash'; import { Alert } from '../../../../../../alerting/common'; import { usePluginContext } from '../../../../hooks/use_plugin_context'; -import { SectionContainer } from '..'; const ALL_TYPES = 'ALL_TYPES'; const allTypes = { @@ -39,102 +40,100 @@ interface Props { export function AlertsSection({ alerts }: Props) { const { config, core } = usePluginContext(); const [filter, setFilter] = useState(ALL_TYPES); - const href = config.unsafe.alertingExperience.enabled - ? '/app/observability/alerts' - : '/app/management/insightsAndAlerting/triggersActions/alerts'; - + const manageLink = config.unsafe.alertingExperience.enabled + ? core.http.basePath.prepend(`/app/observability/alerts`) + : core.http.basePath.prepend(`/app/management/insightsAndAlerting/triggersActions/rules`); const filterOptions = uniqBy(alerts, (alert) => alert.consumer).map(({ consumer }) => ({ value: consumer, text: consumer, })); return ( - - +
+ - - - setFilter(e.target.value)} - prepend={i18n.translate('xpack.observability.overview.alert.view', { - defaultMessage: 'View', - })} - /> - - + +

+ {i18n.translate('xpack.observability.overview.alerts.title', { + defaultMessage: 'Alerts', + })} +

+
- - - {alerts - .filter((alert) => filter === ALL_TYPES || alert.consumer === filter) - .map((alert, index) => { - const isLastElement = index === alerts.length - 1; - return ( - - - - - {alert.name} - - - - - - {alert.alertTypeId} - - {alert.tags.map((tag, idx) => { - return ( - - {tag} - - ); - })} - - - - - - - Updated {moment.duration(moment().diff(alert.updatedAt)).humanize()} ago - - - {alert.muteAll && ( - - - - )} - - - {!isLastElement && } - - ); + + + {i18n.translate('xpack.observability.overview.alert.appLink', { + defaultMessage: 'Manage alerts', })} +
- + <> + + + setFilter(e.target.value)} + /> + + + {alerts + .filter((alert) => filter === ALL_TYPES || alert.consumer === filter) + .map((alert, index) => { + const isLastElement = index === alerts.length - 1; + return ( + + + + {alert.name} + + + + + + {alert.alertTypeId} + + {alert.tags.map((tag, idx) => { + return ( + + {tag} + + ); + })} + + + + + + + Updated {moment.duration(moment().diff(alert.updatedAt)).humanize()} ago + + + {alert.muteAll && ( + + + + )} + + + {!isLastElement && } + + ); + })} + +
); } diff --git a/x-pack/plugins/observability/public/components/app/section/index.tsx b/x-pack/plugins/observability/public/components/app/section/index.tsx index cbe0c45bbd169..a983f4e1fae92 100644 --- a/x-pack/plugins/observability/public/components/app/section/index.tsx +++ b/x-pack/plugins/observability/public/components/app/section/index.tsx @@ -37,7 +37,9 @@ export function SectionContainer({ title, appLink, children, hasError }: Props) } extraAction={ appLink?.href && ( - {appLink.label} + + {appLink.label} + ) } > diff --git a/x-pack/plugins/observability/public/components/app/section/metrics/host_link.tsx b/x-pack/plugins/observability/public/components/app/section/metrics/host_link.tsx index 921cec4222ea0..81a641bb02a5b 100644 --- a/x-pack/plugins/observability/public/components/app/section/metrics/host_link.tsx +++ b/x-pack/plugins/observability/public/components/app/section/metrics/host_link.tsx @@ -4,67 +4,19 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { EuiIcon } from '@elastic/eui'; import React from 'react'; import { StringOrNull } from '../../../..'; -import aixLogo from './logos/aix.svg'; -import androidLogo from './logos/android.svg'; -import darwinLogo from './logos/darwin.svg'; -import dragonflyLogo from './logos/dragonfly.svg'; -import freebsdLogo from './logos/freebsd.svg'; -import illumosLogo from './logos/illumos.svg'; -import linuxLogo from './logos/linux.svg'; -import solarisLogo from './logos/solaris.svg'; -import netbsdLogo from './logos/netbsd.svg'; - interface Props { name: StringOrNull; id: StringOrNull; - provider: StringOrNull; - platform: StringOrNull; timerange: { from: number; to: number }; } -export function HostLink({ name, id, provider, platform, timerange }: Props) { - const providerLogo = - provider === 'aws' - ? 'logoAWS' - : provider === 'gcp' - ? 'logoGCP' - : provider === 'azure' - ? 'logoAzure' - : 'compute'; - - const platformLogo = - platform === 'darwin' - ? darwinLogo - : platform === 'windows' - ? 'logoWindows' - : platform === 'linux' - ? linuxLogo - : platform === 'aix' - ? aixLogo - : platform === 'andriod' - ? androidLogo - : platform === 'dragonfly' - ? dragonflyLogo - : platform === 'illumos' - ? illumosLogo - : platform === 'freebsd' - ? freebsdLogo - : platform === 'solaris' - ? solarisLogo - : platform === 'netbsd' - ? netbsdLogo - : 'empty'; +export function HostLink({ name, id, timerange }: Props) { const link = `../../app/metrics/link-to/host-detail/${id}?from=${timerange.from}&to=${timerange.to}`; return ( <> - {platformLogo !== null && } -   - {providerLogo !== null && } -   {name} ); diff --git a/x-pack/plugins/observability/public/components/app/section/metrics/index.tsx b/x-pack/plugins/observability/public/components/app/section/metrics/index.tsx index 2f5bb9bac9348..fd1e356f849a2 100644 --- a/x-pack/plugins/observability/public/components/app/section/metrics/index.tsx +++ b/x-pack/plugins/observability/public/components/app/section/metrics/index.tsx @@ -30,7 +30,6 @@ import { HostLink } from './host_link'; import { formatDuration } from './lib/format_duration'; import { MetricWithSparkline } from './metric_with_sparkline'; -const SPARK_LINE_COLUMN_WIDTH = '120px'; const COLOR_ORANGE = 7; const COLOR_BLUE = 1; const COLOR_GREEN = 0; @@ -120,12 +119,11 @@ export function MetricsSection({ bucketSize }: Props) { sortable: true, truncateText: true, isExpander: true, + textOnly: true, render: (value: StringOrNull, record: MetricsFetchDataSeries) => ( ), @@ -136,7 +134,6 @@ export function MetricsSection({ bucketSize }: Props) { defaultMessage: 'CPU %', }), sortable: true, - width: SPARK_LINE_COLUMN_WIDTH, render: (value: NumberOrNull, record: MetricsFetchDataSeries) => ( ( ( ( { - return (values ?? []).map(({ label, count }) => ({ + const uniqueValues: Record = {}; + + values?.forEach(({ label, count }) => { + uniqueValues[label] = count; + }); + + return Object.entries(uniqueValues).map(([label, count]) => ({ label, append: showCount ? ( @@ -50,6 +57,7 @@ export function FieldValueSelection({ fullWidth, label, loading, + query, setQuery, button, width, @@ -118,7 +126,7 @@ export function FieldValueSelection({ hasActiveFilters={numOfFilters > 0} iconType="arrowDown" numActiveFilters={numOfFilters} - numFilters={values.length} + numFilters={options.length} onClick={onButtonClick} > {label} @@ -158,19 +166,28 @@ export function FieldValueSelection({ }), compressed, onInput: onValueChange, + 'data-test-subj': 'suggestionInputField', }} listProps={{ onFocusBadge: false, }} options={options} onChange={onChange} - isLoading={loading} + isLoading={loading && !query && options.length === 0} allowExclusions={true} > {(list, search) => (
{search} {list} + {loading && query && ( + + {i18n.translate('xpack.observability.fieldValueSelection.loading', { + defaultMessage: 'Loading', + })}{' '} + + + )} { + jest.spyOn(HTMLElement.prototype, 'offsetHeight', 'get').mockReturnValue(1500); + jest.spyOn(HTMLElement.prototype, 'offsetWidth', 'get').mockReturnValue(1500); + + function setupSearch(data: any) { + // @ts-ignore + jest.spyOn(searchHook, 'useEsSearch').mockReturnValue({ + data: { + took: 17, + timed_out: false, + _shards: { total: 35, successful: 35, skipped: 31, failed: 0 }, + hits: { total: { value: 15299, relation: 'eq' }, hits: [] }, + aggregations: { + values: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: data, + }, + }, + }, + loading: false, + }); + } + + it('renders a list', async () => { + setupSearch([ + { key: 'US', doc_count: 14132 }, + { key: 'Pak', doc_count: 200 }, + { key: 'Japan', doc_count: 100 }, + ]); + + render( + + {}} + selectedValue={[]} + filters={[]} + asCombobox={false} + /> + + ); + + fireEvent.click(screen.getByText('Service name')); + + expect(await screen.findByPlaceholderText('Filter Service name')).toBeInTheDocument(); + expect(await screen.findByText('Apply')).toBeInTheDocument(); + expect(await screen.findByText('US')).toBeInTheDocument(); + expect(await screen.findByText('Pak')).toBeInTheDocument(); + expect(await screen.findByText('Japan')).toBeInTheDocument(); + expect(await screen.findByText('14132')).toBeInTheDocument(); + expect(await screen.findByText('200')).toBeInTheDocument(); + expect(await screen.findByText('100')).toBeInTheDocument(); + + setupSearch([{ key: 'US', doc_count: 14132 }]); + + fireEvent.input(screen.getByTestId('suggestionInputField'), { + target: { value: 'u' }, + }); + + expect(await screen.findByDisplayValue('u')).toBeInTheDocument(); + }); + + it('calls oncChange when applied', async () => { + setupSearch([ + { key: 'US', doc_count: 14132 }, + { key: 'Pak', doc_count: 200 }, + { key: 'Japan', doc_count: 100 }, + ]); + + const onChange = jest.fn(); + + const { rerender } = render( + + + + ); + + fireEvent.click(screen.getByText('Service name')); + + fireEvent.click(await screen.findByText('US')); + fireEvent.click(await screen.findByText('Apply')); + + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenCalledWith(['US'], []); + + rerender( + + + + ); + + fireEvent.click(await screen.findByText('US')); + fireEvent.click(await screen.findByText('Pak')); + fireEvent.click(await screen.findByText('Apply')); + + expect(onChange).toHaveBeenCalledTimes(2); + expect(onChange).toHaveBeenLastCalledWith([], ['US']); + }); +}); diff --git a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/index.tsx b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/index.tsx index 2b4d9c0898f3e..54114c7604644 100644 --- a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/index.tsx +++ b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/index.tsx @@ -6,8 +6,6 @@ */ import React, { useState } from 'react'; - -import useDebounce from 'react-use/lib/useDebounce'; import { useValuesList } from '../../../hooks/use_values_list'; import { FieldValueSelection } from './field_value_selection'; import { FieldValueSuggestionsProps } from './types'; @@ -35,7 +33,6 @@ export function FieldValueSuggestions({ onChange: onSelectionChange, }: FieldValueSuggestionsProps) { const [query, setQuery] = useState(''); - const [debouncedValue, setDebouncedValue] = useState(''); const { values, loading } = useValuesList({ indexPatternTitle, @@ -46,14 +43,6 @@ export function FieldValueSuggestions({ keepHistory: true, }); - useDebounce( - () => { - setQuery(debouncedValue); - }, - 400, - [debouncedValue] - ); - const SelectionComponent = asCombobox ? FieldValueCombobox : FieldValueSelection; return ( @@ -63,7 +52,8 @@ export function FieldValueSuggestions({ values={values} label={label} onChange={onSelectionChange} - setQuery={setDebouncedValue} + query={query} + setQuery={setQuery} loading={loading} selectedValue={selectedValue} excludedValue={excludedValue} diff --git a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/types.ts b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/types.ts index aa8c967e31ff5..d857b39b074ac 100644 --- a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/types.ts +++ b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/types.ts @@ -39,6 +39,7 @@ export type FieldValueSelectionProps = CommonProps & { loading?: boolean; onChange: (val?: string[], excludedValue?: string[]) => void; values?: ListItem[]; + query?: string; setQuery: Dispatch>; }; diff --git a/x-pack/plugins/observability/public/hooks/use_values_list.ts b/x-pack/plugins/observability/public/hooks/use_values_list.ts index 094b7a0f36921..46d89a062f072 100644 --- a/x-pack/plugins/observability/public/hooks/use_values_list.ts +++ b/x-pack/plugins/observability/public/hooks/use_values_list.ts @@ -58,6 +58,13 @@ export const useValuesList = ({ [query] ); + useEffect(() => { + if (!query) { + // in case query is cleared, we don't wait for debounce + setDebounceQuery(query); + } + }, [query]); + const { data, loading } = useEsSearch( createEsParams({ index: indexPatternTitle!, diff --git a/x-pack/plugins/observability/public/pages/overview/index.tsx b/x-pack/plugins/observability/public/pages/overview/index.tsx index fdb52270befed..71c52c3a51d3b 100644 --- a/x-pack/plugins/observability/public/pages/overview/index.tsx +++ b/x-pack/plugins/observability/public/pages/overview/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { useTrackPageview } from '../..'; @@ -91,27 +91,22 @@ export function OverviewPage({ routeParams }: Props) { {/* Data sections */} {hasAnyData && } - - - - {/* Alert section */} - {!!alerts.length && ( - - - - )} - - {/* Resources section */} - - - - + + + + {/* Resources / What's New sections */} + + + + {!!newsFeed?.items?.length && } + - - {!!newsFeed?.items?.length && ( - - + {!!alerts.length && ( + + + + )} diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts index f650bbaed1271..709c0ccd67e9c 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/check_cells_for_formulas.ts @@ -6,7 +6,7 @@ */ import { pick, keys, values, some } from 'lodash'; -import { cellHasFormulas } from '../../csv_searchsource/generate_csv/cell_has_formula'; +import { cellHasFormulas } from '../../../../../../../src/plugins/data/common'; interface IFlattened { [header: string]: string; diff --git a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts index e5ed04f4cab66..c1018030827c0 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/generate_csv/index.ts @@ -8,12 +8,12 @@ import { i18n } from '@kbn/i18n'; import { ElasticsearchClient, IUiSettingsClient } from 'src/core/server'; import { ReportingConfig } from '../../../'; +import { createEscapeValue } from '../../../../../../../src/plugins/data/common'; import { CancellationToken } from '../../../../../../plugins/reporting/common'; import { CSV_BOM_CHARS } from '../../../../common/constants'; import { byteSizeValueToNumber } from '../../../../common/schema_utils'; import { LevelLogger } from '../../../lib'; import { getFieldFormats } from '../../../services'; -import { createEscapeValue } from '../../csv_searchsource/generate_csv/escape_value'; import { MaxSizeStringBuilder } from '../../csv_searchsource/generate_csv/max_size_string_builder'; import { IndexPatternSavedObjectDeprecatedCSV, diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/cell_has_formula.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/cell_has_formula.ts deleted file mode 100644 index aa361fcfbc195..0000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/cell_has_formula.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { startsWith } from 'lodash'; -import { CSV_FORMULA_CHARS } from '../../../../common/constants'; - -export const cellHasFormulas = (val: string) => - CSV_FORMULA_CHARS.some((formulaChar) => startsWith(val, formulaChar)); diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts index 1d70b656fed36..254bc0ae21f6c 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/generate_csv.ts @@ -22,6 +22,7 @@ import { SearchFieldValue, SearchSourceFields, tabifyDocs, + cellHasFormulas, } from '../../../../../../../src/plugins/data/common'; import { KbnServerError } from '../../../../../../../src/plugins/kibana_utils/server'; import { CancellationToken } from '../../../../common'; @@ -30,7 +31,6 @@ import { byteSizeValueToNumber } from '../../../../common/schema_utils'; import { LevelLogger } from '../../../lib'; import { TaskRunResult } from '../../../lib/tasks'; import { JobParamsCSV } from '../types'; -import { cellHasFormulas } from './cell_has_formula'; import { CsvExportSettings, getExportSettings } from './get_export_settings'; import { MaxSizeStringBuilder } from './max_size_string_builder'; diff --git a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/get_export_settings.ts b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/get_export_settings.ts index 17a10f3034242..0b8815836367f 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/get_export_settings.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_searchsource/generate_csv/get_export_settings.ts @@ -8,6 +8,7 @@ import { ByteSizeValue } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; import { IUiSettingsClient } from 'kibana/server'; +import { createEscapeValue } from '../../../../../../../src/plugins/data/common'; import { ReportingConfig } from '../../../'; import { CSV_BOM_CHARS, @@ -16,7 +17,6 @@ import { UI_SETTINGS_CSV_SEPARATOR, } from '../../../../common/constants'; import { LevelLogger } from '../../../lib'; -import { createEscapeValue } from './escape_value'; export interface CsvExportSettings { timezone: string; diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts index e30cde4989284..10ed18eb91d0c 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/custom_query_rule.spec.ts @@ -88,6 +88,7 @@ import { import { changeRowsPerPageTo100, deleteFirstRule, + deleteRuleFromDetailsPage, deleteSelectedRules, editFirstRule, filterByCustomRules, @@ -237,8 +238,10 @@ describe('Custom detection rules deletion and edition', () => { goToManageAlertsDetectionRules(); waitForAlertsIndexToBeCreated(); createCustomRuleActivated(getNewRule(), 'rule1'); - createCustomRuleActivated(getNewOverrideRule(), 'rule2'); - createCustomRuleActivated(getExistingRule(), 'rule3'); + createCustomRuleActivated(getNewRule(), 'rule2'); + + createCustomRuleActivated(getNewOverrideRule(), 'rule3'); + createCustomRuleActivated(getExistingRule(), 'rule4'); reload(); }); @@ -292,7 +295,7 @@ describe('Custom detection rules deletion and edition', () => { }); cy.get(SHOWING_RULES_TEXT).should( 'have.text', - `Showing ${expectedNumberOfRulesAfterDeletion} rule` + `Showing ${expectedNumberOfRulesAfterDeletion} rules` ); cy.get(CUSTOM_RULES_BTN).should( 'have.text', @@ -300,6 +303,38 @@ describe('Custom detection rules deletion and edition', () => { ); }); }); + + it('Deletes one rule from detail page', () => { + cy.get(RULES_TABLE) + .find(RULES_ROW) + .then((rules) => { + const initialNumberOfRules = rules.length; + const expectedNumberOfRulesAfterDeletion = initialNumberOfRules - 1; + + goToRuleDetails(); + cy.intercept('POST', '/api/detection_engine/rules/_bulk_delete').as('deleteRule'); + + deleteRuleFromDetailsPage(); + + cy.waitFor('@deleteRule').then(() => { + cy.get(RULES_TABLE).should('exist'); + cy.get(RULES_TABLE).then(($table) => { + cy.wrap($table.find(RULES_ROW).length).should( + 'eql', + expectedNumberOfRulesAfterDeletion + ); + }); + cy.get(SHOWING_RULES_TEXT).should( + 'have.text', + `Showing ${expectedNumberOfRulesAfterDeletion} rules` + ); + cy.get(CUSTOM_RULES_BTN).should( + 'have.text', + `Custom rules (${expectedNumberOfRulesAfterDeletion})` + ); + }); + }); + }); }); context('Edition', () => { diff --git a/x-pack/plugins/security_solution/cypress/integration/overview/cti_link_panel.spec.ts b/x-pack/plugins/security_solution/cypress/integration/overview/cti_link_panel.spec.ts new file mode 100644 index 0000000000000..514c4b4e12bb3 --- /dev/null +++ b/x-pack/plugins/security_solution/cypress/integration/overview/cti_link_panel.spec.ts @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + OVERVIEW_CTI_ENABLE_MODULE_BUTTON, + OVERVIEW_CTI_LINKS, + OVERVIEW_CTI_LINKS_ERROR_INNER_PANEL, + OVERVIEW_CTI_LINKS_INFO_INNER_PANEL, + OVERVIEW_CTI_LINKS_WARNING_INNER_PANEL, + OVERVIEW_CTI_TOTAL_EVENT_COUNT, + OVERVIEW_CTI_VIEW_DASHBOARD_BUTTON, +} from '../../screens/overview'; + +import { loginAndWaitForPage } from '../../tasks/login'; +import { OVERVIEW_URL } from '../../urls/navigation'; +import { cleanKibana } from '../../tasks/common'; +import { esArchiverLoad, esArchiverUnload } from '../../tasks/es_archiver'; + +describe('CTI Link Panel', () => { + before(() => { + cleanKibana(); + }); + + it('renders disabled threat intel module as expected', () => { + loginAndWaitForPage(OVERVIEW_URL); + cy.get(`${OVERVIEW_CTI_LINKS} ${OVERVIEW_CTI_LINKS_ERROR_INNER_PANEL}`).should('exist'); + cy.get(`${OVERVIEW_CTI_VIEW_DASHBOARD_BUTTON}`).should('be.disabled'); + cy.get(`${OVERVIEW_CTI_TOTAL_EVENT_COUNT}`).should('have.text', 'Showing: 0 indicators'); + cy.get(`${OVERVIEW_CTI_ENABLE_MODULE_BUTTON}`).should('exist'); + cy.get(`${OVERVIEW_CTI_ENABLE_MODULE_BUTTON}`).should( + 'have.attr', + 'href', + 'https://www.elastic.co/guide/en/beats/filebeat/master/filebeat-module-threatintel.html' + ); + }); + + describe('enabled threat intel module', () => { + before(() => { + esArchiverLoad('threat_indicator'); + }); + + after(() => { + esArchiverUnload('threat_indicator'); + }); + + it('renders disabled dashboard module as expected when there are no events in the selected time period', () => { + loginAndWaitForPage( + `${OVERVIEW_URL}?sourcerer=(timerange:(from:%272021-07-08T04:00:00.000Z%27,kind:absolute,to:%272021-07-09T03:59:59.999Z%27))` + ); + cy.get(`${OVERVIEW_CTI_LINKS} ${OVERVIEW_CTI_LINKS_WARNING_INNER_PANEL}`).should('exist'); + cy.get(`${OVERVIEW_CTI_LINKS} ${OVERVIEW_CTI_LINKS_INFO_INNER_PANEL}`).should('exist'); + cy.get(`${OVERVIEW_CTI_VIEW_DASHBOARD_BUTTON}`).should('be.disabled'); + cy.get(`${OVERVIEW_CTI_TOTAL_EVENT_COUNT}`).should('have.text', 'Showing: 0 indicators'); + }); + + it('renders dashboard module as expected when there are events in the selected time period', () => { + loginAndWaitForPage(OVERVIEW_URL); + cy.get(`${OVERVIEW_CTI_LINKS} ${OVERVIEW_CTI_LINKS_WARNING_INNER_PANEL}`).should('not.exist'); + cy.get(`${OVERVIEW_CTI_LINKS} ${OVERVIEW_CTI_LINKS_INFO_INNER_PANEL}`).should('exist'); + cy.get(`${OVERVIEW_CTI_VIEW_DASHBOARD_BUTTON}`).should('be.disabled'); + cy.get(`${OVERVIEW_CTI_TOTAL_EVENT_COUNT}`).should('have.text', 'Showing: 1 indicator'); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/cypress/screens/alerts_detection_rules.ts b/x-pack/plugins/security_solution/cypress/screens/alerts_detection_rules.ts index 0bf0e5a09e328..9a23d98c1e91f 100644 --- a/x-pack/plugins/security_solution/cypress/screens/alerts_detection_rules.ts +++ b/x-pack/plugins/security_solution/cypress/screens/alerts_detection_rules.ts @@ -103,3 +103,5 @@ export const RULES_EMPTY_PROMPT = '[data-test-subj="rulesEmptyPrompt"]'; export const RULES_DELETE_CONFIRMATION_MODAL = '[data-test-subj="allRulesDeleteConfirmationModal"]'; export const MODAL_CONFIRMATION_BTN = '[data-test-subj="confirmModalConfirmButton"]'; + +export const RULE_DETAILS_DELETE_BTN = '[data-test-subj="rules-details-delete-rule"]'; diff --git a/x-pack/plugins/security_solution/cypress/screens/overview.ts b/x-pack/plugins/security_solution/cypress/screens/overview.ts index ce6c5662ecb9e..b505bc3b01848 100644 --- a/x-pack/plugins/security_solution/cypress/screens/overview.ts +++ b/x-pack/plugins/security_solution/cypress/screens/overview.ts @@ -147,3 +147,11 @@ export const OVERVIEW_NETWORK_STATS = '[data-test-subj="overview-network-stats"] export const OVERVIEW_EMPTY_PAGE = '[data-test-subj="empty-page"]'; export const OVERVIEW_REVENT_TIMELINES = '[data-test-subj="overview-recent-timelines"]'; + +export const OVERVIEW_CTI_LINKS = '[data-test-subj="cti-dashboard-links"]'; +export const OVERVIEW_CTI_LINKS_ERROR_INNER_PANEL = '[data-test-subj="cti-inner-panel-danger"]'; +export const OVERVIEW_CTI_LINKS_WARNING_INNER_PANEL = '[data-test-subj="cti-inner-panel-warning"]'; +export const OVERVIEW_CTI_LINKS_INFO_INNER_PANEL = '[data-test-subj="cti-inner-panel-info"]'; +export const OVERVIEW_CTI_VIEW_DASHBOARD_BUTTON = '[data-test-subj="cti-view-dashboard-button"]'; +export const OVERVIEW_CTI_TOTAL_EVENT_COUNT = `${OVERVIEW_CTI_LINKS} [data-test-subj="header-panel-subtitle"]`; +export const OVERVIEW_CTI_ENABLE_MODULE_BUTTON = '[data-test-subj="cti-enable-module-button"]'; diff --git a/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts b/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts index a260f3ec48955..6dbd1ae16c4ad 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/alerts_detection_rules.ts @@ -42,6 +42,7 @@ import { ACTIVATE_RULE_BULK_BTN, DEACTIVATE_RULE_BULK_BTN, EXPORT_RULE_BULK_BTN, + RULE_DETAILS_DELETE_BTN, } from '../screens/alerts_detection_rules'; import { ALL_ACTIONS, DELETE_RULE } from '../screens/rule_details'; @@ -107,6 +108,17 @@ export const deleteSelectedRules = () => { cy.get(DELETE_RULE_BULK_BTN).click(); }; +export const deleteRuleFromDetailsPage = () => { + cy.get(ALL_ACTIONS).should('be.visible'); + cy.root() + .pipe(($el) => { + $el.find(ALL_ACTIONS).trigger('click'); + return $el.find(RULE_DETAILS_DELETE_BTN); + }) + .should(($el) => expect($el).to.be.visible); + cy.get(RULE_DETAILS_DELETE_BTN).pipe(($el) => $el.trigger('click')); +}; + export const duplicateSelectedRules = () => { cy.get(BULK_ACTIONS_BTN).click({ force: true }); cy.get(DUPLICATE_RULE_BULK_BTN).click(); @@ -143,7 +155,7 @@ export const goToCreateNewRule = () => { }; export const goToRuleDetails = () => { - cy.get(RULE_NAME).click({ force: true }); + cy.get(RULE_NAME).first().click({ force: true }); }; export const loadPrebuiltDetectionRules = () => { diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/enrichment_icon.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/enrichment_icon.tsx index 042940a1cf036..e1e35b0d2c5c5 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/enrichment_icon.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/enrichment_icon.tsx @@ -24,7 +24,7 @@ export const getTooltipContent = (type: string | undefined) => export const EnrichmentIcon: React.FC<{ type: string | undefined }> = ({ type }) => { return ( - + ); }; diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.tsx index b521c3ba92c4d..a26e74d12f40f 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.tsx @@ -41,7 +41,7 @@ export const NoEnrichmentsPanel: React.FC<{ const threatIntelDocsUrl = `${ useKibana().services.docLinks.links.filebeat.base }/filebeat-module-threatintel.html`; - const noIndicatorEnrichmentsDescription = ( + const noIntelligenceCTA = ( <> {i18n.IF_CTI_NOT_ENABLED} @@ -55,10 +55,9 @@ export const NoEnrichmentsPanel: React.FC<{ {i18n.NO_ENRICHMENTS_FOUND_TITLE}

} description={ - <> -

{noIndicatorEnrichmentsDescription}

-

{i18n.NO_INVESTIGATION_ENRICHMENTS_DESCRIPTION}

- +

+ {i18n.NO_ENRICHMENTS_FOUND_DESCRIPTION} {noIntelligenceCTA} +

} /> ); @@ -68,7 +67,11 @@ export const NoEnrichmentsPanel: React.FC<{ {i18n.NO_INDICATOR_ENRICHMENTS_TITLE}

} - description={noIndicatorEnrichmentsDescription} + description={ +

+ {i18n.NO_INDICATOR_ENRICHMENTS_DESCRIPTION} {noIntelligenceCTA} +

+ } /> ); @@ -78,7 +81,11 @@ export const NoEnrichmentsPanel: React.FC<{ {i18n.NO_INVESTIGATION_ENRICHMENTS_TITLE}} - description={i18n.NO_INVESTIGATION_ENRICHMENTS_DESCRIPTION} + description={ +

+ {i18n.NO_INVESTIGATION_ENRICHMENTS_DESCRIPTION} {noIntelligenceCTA} +

+ } /> ); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx index b6b8a47c1dd8c..27761c9296710 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx @@ -48,13 +48,10 @@ const ThreatDetailsHeader: React.FC<{ }> = ({ field, value, provider, type }) => ( <> - - - - + - {field} {value} + {field} {value} {provider && ( @@ -66,6 +63,9 @@ const ThreatDetailsHeader: React.FC<{
)} + + + diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_summary_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_summary_view.tsx index 4a6c9ec48bcbc..274e292f5d1c2 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_summary_view.tsx +++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_summary_view.tsx @@ -32,17 +32,17 @@ export interface ThreatSummaryItem { } const RightMargin = styled.span` - margin-right: ${({ theme }) => theme.eui.paddingSizes.s}; + margin-right: ${({ theme }) => theme.eui.paddingSizes.xs}; `; const EnrichmentTitle: React.FC = ({ title, type }) => ( <> - + +
{title}
+
- -
{title}
-
+ ); diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/translations.ts b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/translations.ts index df4fd8b88d38f..965b7da7e5ed3 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/translations.ts +++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/translations.ts @@ -17,14 +17,14 @@ export const PROVIDER_PREPOSITION = i18n.translate( export const INDICATOR_TOOLTIP_TITLE = i18n.translate( 'xpack.securitySolution.eventDetails.ctiSummary.indicatorEnrichmentTooltipTitle', { - defaultMessage: 'Indicator rule enrichment', + defaultMessage: 'Threat Match Detected', } ); export const INVESTIGATION_TOOLTIP_TITLE = i18n.translate( 'xpack.securitySolution.eventDetails.ctiSummary.investigationEnrichmentTooltipTitle', { - defaultMessage: 'Investigation time enrichment', + defaultMessage: 'Enriched with Threat Intelligence', } ); @@ -32,7 +32,7 @@ export const INDICATOR_TOOLTIP_CONTENT = i18n.translate( 'xpack.securitySolution.eventDetails.ctiSummary.indicatorEnrichmentTooltipContent', { defaultMessage: - 'This field matched a known indicator, and was enriched by an indicator match rule. See more details on the Threat Intel tab.', + 'This field value matched a threat intelligence indicator with a rule you created.', } ); @@ -40,42 +40,51 @@ export const INVESTIGATION_TOOLTIP_CONTENT = i18n.translate( 'xpack.securitySolution.eventDetails.ctiSummary.investigationEnrichmentTooltipContent', { defaultMessage: - 'This field matched a known indicator; see more details on the Threat Intel tab.', + 'This field value has additional information available from threat intelligence sources.', } ); export const NO_INDICATOR_ENRICHMENTS_TITLE = i18n.translate( 'xpack.securitySolution.alertDetails.noIndicatorEnrichmentsTitle', { - defaultMessage: 'No indicator match rule enrichments found', + defaultMessage: 'No Indicator Matches Found', + } +); + +export const NO_INDICATOR_ENRICHMENTS_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.alertDetails.noIndicatorEnrichmentsDescription', + { + defaultMessage: + 'We did not find any threat intelligence indicators with any of the indicator match rules.', } ); export const NO_INVESTIGATION_ENRICHMENTS_TITLE = i18n.translate( 'xpack.securitySolution.alertDetails.noInvestigationEnrichmentsTitle', { - defaultMessage: 'No investigation time enrichments found', + defaultMessage: 'No Threat Intelligence Enrichment Found', } ); export const NO_INVESTIGATION_ENRICHMENTS_DESCRIPTION = i18n.translate( 'xpack.securitySolution.alertDetails.noInvestigationEnrichmentsDescription', { - defaultMessage: "We haven't found any indicator matches from the last 30 days.", + defaultMessage: 'We did not find any threat intelligence in last 30 days to enrich this alert.', } ); export const NO_ENRICHMENTS_FOUND_TITLE = i18n.translate( 'xpack.securitySolution.alertDetails.noEnrichmentsFoundTitle', { - defaultMessage: 'No indicator match rule or investigation time enrichments found', + defaultMessage: 'No Indicator Match or Threat Intel Enrichment Found', } ); export const NO_ENRICHMENTS_FOUND_DESCRIPTION = i18n.translate( - 'xpack.securitySolution.alertDetails.noEnrichmentFoundDescription', + 'xpack.securitySolution.alertDetails.noEnrichmentsFoundDescription', { - defaultMessage: 'No indicator match rule or investigation time enrichments found', + defaultMessage: + 'We did not find threat intelligence that matches any of the indicator match rules, or any enrichment for this alert.', } ); @@ -94,6 +103,6 @@ export const CHECK_DOCS = i18n.translate('xpack.securitySolution.alertDetails.ch export const INVESTIGATION_QUERY_TITLE = i18n.translate( 'xpack.securitySolution.alertDetails.investigationTimeQueryTitle', { - defaultMessage: 'Investigation time enrichment', + defaultMessage: 'Enrichment with Threat Intelligence', } ); diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.test.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.test.tsx index cf9407a6bf463..d3e1dea2dd93e 100644 --- a/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.test.tsx @@ -19,6 +19,7 @@ import { getFormattedEntries, getFormattedEntry, getUpdatedEntriesOnDelete, + customValidators, } from './helpers'; import { ThreatMapEntry } from '@kbn/securitysolution-io-ts-alerting-types'; @@ -294,4 +295,19 @@ describe('Helpers', () => { expect(items).toEqual([{ entries: [entry] }]); }); }); + + describe('customValidators.forbiddenField', () => { + const FORBIDDEN = '*'; + + test('it returns expected value when a forbidden value is passed in', () => { + expect(customValidators.forbiddenField('*', FORBIDDEN)).toEqual({ + code: 'ERR_FIELD_FORMAT', + message: 'The index pattern cannot be *. Please choose a more specific index pattern.', + }); + }); + + test('it returns undefined when a non-forbidden value is passed in', () => { + expect(customValidators.forbiddenField('.test-index', FORBIDDEN)).not.toBeDefined(); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx b/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx index 232fac4ad8433..89ace117f1301 100644 --- a/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx +++ b/x-pack/plugins/security_solution/public/common/components/threat_match/helpers.tsx @@ -6,11 +6,14 @@ */ import uuid from 'uuid'; +import { i18n } from '@kbn/i18n'; import { addIdToItem } from '@kbn/securitysolution-utils'; import { ThreatMap, threatMap, ThreatMapping } from '@kbn/securitysolution-io-ts-alerting-types'; import { IndexPattern, IFieldType } from '../../../../../../../src/plugins/data/common'; import { Entry, FormattedEntry, ThreatMapEntries, EmptyEntry } from './types'; +import { ValidationFunc } from '../../../../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib'; +import { ERROR_CODE } from '../../../../../../../src/plugins/es_ui_shared/static/forms/helpers/field_validators/types'; /** * Formats the entry into one that is easily usable for the UI. @@ -178,3 +181,36 @@ export const singleEntryThreat = (items: ThreatMapEntries[]): boolean => { items[0].entries[0].value === '' ); }; + +export const customValidators = { + forbiddenField: ( + value: unknown, + forbiddenString: string + ): ReturnType> => { + let match: boolean; + + if (typeof value === 'string') { + match = value === forbiddenString; + } else if (Array.isArray(value)) { + match = !!value.find((item) => item === forbiddenString); + } else { + match = false; + } + + if (match) { + return { + code: 'ERR_FIELD_FORMAT', + message: i18n.translate( + 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.threatMatchIndexForbiddenError', + { + defaultMessage: + 'The index pattern cannot be { forbiddenString }. Please choose a more specific index pattern.', + values: { + forbiddenString, + }, + } + ), + }; + } + }, +}; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx index 2146123deafd5..9f2728e0813f4 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_overflow/index.tsx @@ -16,7 +16,6 @@ import React, { useCallback, useMemo } from 'react'; import styled from 'styled-components'; import { noop } from 'lodash/fp'; -import { useHistory } from 'react-router-dom'; import { Rule } from '../../../containers/detection_engine/rules'; import * as i18n from './translations'; import * as i18nActions from '../../../pages/detection_engine/rules/translations'; @@ -31,6 +30,7 @@ import { getRulesUrl } from '../../../../common/components/link_to/redirect_to_d import { getToolTipContent } from '../../../../common/utils/privileges'; import { useBoolState } from '../../../../common/hooks/use_bool_state'; import { useKibana } from '../../../../common/lib/kibana'; +import { APP_ID, SecurityPageName } from '../../../../../common/constants'; const MyEuiButtonIcon = styled(EuiButtonIcon)` &.euiButtonIcon { @@ -58,13 +58,15 @@ const RuleActionsOverflowComponent = ({ canDuplicateRuleWithActions, }: RuleActionsOverflowComponentProps) => { const [isPopoverOpen, , closePopover, togglePopover] = useBoolState(); - const history = useHistory(); const { navigateToApp } = useKibana().services.application; const [, dispatchToaster] = useStateToaster(); const onRuleDeletedCallback = useCallback(() => { - history.push(getRulesUrl()); - }, [history]); + navigateToApp(APP_ID, { + deepLinkId: SecurityPageName.rules, + path: getRulesUrl(), + }); + }, [navigateToApp]); const actions = useMemo( () => diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/schema.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/schema.tsx index ace5fd083620c..71fcfdbc49475 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/schema.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/schema.tsx @@ -13,6 +13,7 @@ import React from 'react'; import { singleEntryThreat, containsInvalidItems, + customValidators, } from '../../../../common/components/threat_match/helpers'; import { isThreatMatchRule, isThresholdRule } from '../../../../../common/detection_engine/utils'; import { isMlRule } from '../../../../../common/machine_learning/helpers'; @@ -371,6 +372,19 @@ export const schema: FormSchema = { )(...args); }, }, + { + validator: ( + ...args: Parameters + ): ReturnType> | undefined => { + const [{ formData, value }] = args; + const needsValidation = isThreatMatchRule(formData.ruleType); + if (!needsValidation) { + return; + } + + return customValidators.forbiddenField(value, '*'); + }, + }, ], }, threatMapping: { diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.test.tsx index 2c519fe34412e..a9f48d2103bd4 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.test.tsx @@ -46,9 +46,9 @@ describe('CtiDisabledModule', () => { ); expect( - wrapper.find( - '[data-test-subj="cti-dashboard-links"] [data-test-subj="cti-inner-panel-danger"]' - ).length + wrapper + .find('[data-test-subj="cti-dashboard-links"] [data-test-subj="cti-inner-panel-danger"]') + .hostNodes().length ).toEqual(1); }); }); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.tsx index 1600356882c36..da5216be7db3c 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_disabled_module.tsx @@ -25,11 +25,16 @@ export const CtiDisabledModuleComponent = () => { title={i18n.DANGER_TITLE} body={i18n.DANGER_BODY} button={ - + {i18n.DANGER_BUTTON} } - data-test-subj="cti-inner-panel-danger" + dataTestSubj="cti-inner-panel-danger" /> ), [threatIntelDocLink] diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_inner_panel.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_inner_panel.tsx index ddff78608dfb0..dbdd9ed5526a8 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_inner_panel.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_inner_panel.tsx @@ -35,16 +35,18 @@ export const CtiInnerPanel = ({ title, body, button, + dataTestSubj, }: { color: 'primary' | 'warning'; title: string; body: string; button?: JSX.Element; + dataTestSubj: string; }) => { const iconType = color === 'primary' ? 'iInCircle' : 'help'; return ( - + diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.test.tsx index f00e1053e8082..7ecaccad19d64 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.test.tsx @@ -51,9 +51,9 @@ describe('CtiNoEvents', () => { ); expect( - wrapper.find( - '[data-test-subj="cti-dashboard-links"] [data-test-subj="cti-inner-panel-warning"]' - ).length + wrapper + .find('[data-test-subj="cti-dashboard-links"] [data-test-subj="cti-inner-panel-warning"]') + .hostNodes().length ).toEqual(1); }); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.tsx index 9792b5044eab7..525235142ace1 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/cti_no_events.tsx @@ -17,7 +17,7 @@ const warning = ( color={'warning'} title={i18n.WARNING_TITLE} body={i18n.WARNING_BODY} - data-test-subj="cti-inner-panel-warning" + dataTestSubj="cti-inner-panel-warning" /> ); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.test.tsx index f0e3bcaaec6e0..9714c28cc58cc 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.test.tsx @@ -75,7 +75,7 @@ describe('ThreatIntelPanelView', () => { ); - expect(wrapper.find('[data-test-subj="cti-inner-panel-info"]').length).toEqual(1); + expect(wrapper.find('[data-test-subj="cti-inner-panel-info"]').hostNodes().length).toEqual(1); }); it('does not render info panel if dashboard plugin is disabled', () => { diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx index babbd5d13224f..2add03788eea2 100644 --- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx @@ -95,7 +95,12 @@ export const ThreatIntelPanelView: React.FC = ({ const button = useMemo( () => ( - + = ({ () => isDashboardPluginDisabled ? ( ', () => { await act(async () => { testBed.actions.selectTab('snapshots'); - await delay(100); - testBed.component.update(); }); + + testBed.component.update(); }); test('should display an empty prompt', () => { @@ -438,9 +437,8 @@ describe('', () => { await act(async () => { testBed.actions.selectTab('snapshots'); - await delay(2000); - testBed.component.update(); }); + testBed.component.update(); }); test('should display an empty prompt', () => { @@ -477,9 +475,9 @@ describe('', () => { await act(async () => { testBed.actions.selectTab('snapshots'); - await delay(2000); - testBed.component.update(); }); + + testBed.component.update(); }); test('should list them in the table', async () => { diff --git a/x-pack/plugins/snapshot_restore/server/routes/api/snapshots.test.ts b/x-pack/plugins/snapshot_restore/server/routes/api/snapshots.test.ts index 00543d7081d34..f71c5ec9ffc08 100644 --- a/x-pack/plugins/snapshot_restore/server/routes/api/snapshots.test.ts +++ b/x-pack/plugins/snapshot_restore/server/routes/api/snapshots.test.ts @@ -38,6 +38,7 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => { const getLifecycleFn = router.getMockApiFn('slm.getLifecycle'); const getSnapshotFn = router.getMockApiFn('snapshot.get'); const deleteSnapshotFn = router.getMockApiFn('snapshot.delete'); + const getRepoFn = router.getMockApiFn('snapshot.getRepository'); beforeAll(() => { registerSnapshotsRoutes({ @@ -59,7 +60,7 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => { }; test('combines snapshots and their repositories returned from ES', async () => { - const mockSnapshotGetPolicyEsResponse = { + const mockGetPolicyEsResponse = { fooPolicy: {}, }; @@ -70,12 +71,22 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => { ], }; - getClusterSettingsFn.mockResolvedValue({ body: mockSnapshotGetManagedRepositoryEsResponse }); - getLifecycleFn.mockResolvedValue({ body: mockSnapshotGetPolicyEsResponse }); - getSnapshotFn.mockResolvedValueOnce({ body: mockGetSnapshotsResponse }); + const mockGetRepositoryEsResponse = { + fooRepository: {}, + barRepository: {}, + // Test that there may be a repository that does not yet have any snapshots associated to it + bazRepository: {}, + }; + + getClusterSettingsFn.mockResolvedValue({ + body: mockSnapshotGetManagedRepositoryEsResponse, + }); + getLifecycleFn.mockResolvedValue({ body: mockGetPolicyEsResponse }); + getRepoFn.mockResolvedValue({ body: mockGetRepositoryEsResponse }); + getSnapshotFn.mockResolvedValue({ body: mockGetSnapshotsResponse }); const expectedResponse = { - repositories: ['fooRepository', 'barRepository'], + repositories: ['fooRepository', 'barRepository', 'bazRepository'], policies: ['fooPolicy'], snapshots: [ { @@ -104,7 +115,7 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => { }); test('returns an error object if ES request contains repository failures', async () => { - const mockSnapshotGetPolicyEsResponse = { + const mockGetPolicyEsResponse = { fooPolicy: {}, }; @@ -119,9 +130,16 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => { }, }; - getClusterSettingsFn.mockResolvedValue({ body: mockSnapshotGetManagedRepositoryEsResponse }); - getLifecycleFn.mockResolvedValue({ body: mockSnapshotGetPolicyEsResponse }); - getSnapshotFn.mockResolvedValueOnce({ body: mockGetSnapshotsResponse }); + const mockGetRepositoryEsResponse = { + fooRepository: {}, + }; + + getClusterSettingsFn.mockResolvedValue({ + body: mockSnapshotGetManagedRepositoryEsResponse, + }); + getLifecycleFn.mockResolvedValue({ body: mockGetPolicyEsResponse }); + getRepoFn.mockResolvedValue({ body: mockGetRepositoryEsResponse }); + getSnapshotFn.mockResolvedValue({ body: mockGetSnapshotsResponse }); const expectedResponse = { repositories: ['fooRepository'], @@ -150,13 +168,12 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => { expect(response).toEqual({ body: expectedResponse }); }); - test('returns empty arrays if no snapshots returned from ES', async () => { - const mockSnapshotGetPolicyEsResponse = {}; - const mockSnapshotGetRepositoryEsResponse = {}; - - getClusterSettingsFn.mockResolvedValue({ body: mockSnapshotGetManagedRepositoryEsResponse }); - getLifecycleFn.mockResolvedValue({ body: mockSnapshotGetPolicyEsResponse }); - getSnapshotFn.mockResolvedValue({ body: mockSnapshotGetRepositoryEsResponse }); + test('returns empty arrays if no repositories returned from ES', async () => { + getClusterSettingsFn.mockResolvedValue({ + body: mockSnapshotGetManagedRepositoryEsResponse, + }); + getLifecycleFn.mockResolvedValue({ body: {} }); + getRepoFn.mockResolvedValue({ body: {} }); const expectedResponse = { snapshots: [], @@ -168,10 +185,33 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => { expect(response).toEqual({ body: expectedResponse }); }); + test('returns an empty snapshot array if no snapshots returned from ES', async () => { + const mockGetRepositoryEsResponse = { + fooRepository: {}, + }; + + getClusterSettingsFn.mockResolvedValue({ + body: mockSnapshotGetManagedRepositoryEsResponse, + }); + getLifecycleFn.mockResolvedValue({ body: {} }); + getRepoFn.mockResolvedValue({ body: mockGetRepositoryEsResponse }); + getSnapshotFn.mockResolvedValue({ body: {} }); + + const expectedResponse = { + snapshots: [], + repositories: ['fooRepository'], + policies: [], + }; + + const response = await router.runRequest(mockRequest); + expect(response).toEqual({ body: expectedResponse }); + }); + test('throws if ES error', async () => { - getClusterSettingsFn.mockRejectedValueOnce(new Error()); - getLifecycleFn.mockRejectedValueOnce(new Error()); - getSnapshotFn.mockRejectedValueOnce(new Error()); + getClusterSettingsFn.mockRejectedValue(new Error()); + getLifecycleFn.mockRejectedValue(new Error()); + getRepoFn.mockRejectedValue(new Error()); + getSnapshotFn.mockRejectedValue(new Error()); await expect(router.runRequest(mockRequest)).rejects.toThrowError(); }); @@ -197,12 +237,14 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => { }; test('returns snapshot object with repository name if returned from ES', async () => { - const mockSnapshotGetEsResponse = { + const mockGetSnapshotEsResponse = { snapshots: [{ snapshot, repository }], }; - getClusterSettingsFn.mockResolvedValue({ body: mockSnapshotGetManagedRepositoryEsResponse }); - getSnapshotFn.mockResolvedValueOnce({ body: mockSnapshotGetEsResponse }); + getClusterSettingsFn.mockResolvedValue({ + body: mockSnapshotGetManagedRepositoryEsResponse, + }); + getSnapshotFn.mockResolvedValue({ body: mockGetSnapshotEsResponse }); const expectedResponse = { ...defaultSnapshot, @@ -237,8 +279,10 @@ describe('[Snapshot and Restore API Routes] Snapshots', () => { ], }; - getClusterSettingsFn.mockResolvedValue({ body: mockSnapshotGetManagedRepositoryEsResponse }); - getSnapshotFn.mockResolvedValueOnce({ body: mockSnapshotGetEsResponse }); + getClusterSettingsFn.mockResolvedValue({ + body: mockSnapshotGetManagedRepositoryEsResponse, + }); + getSnapshotFn.mockResolvedValue({ body: mockSnapshotGetEsResponse }); await expect(router.runRequest(mockRequest)).resolves.toEqual({ body: 'Snapshot not found', diff --git a/x-pack/plugins/snapshot_restore/server/routes/api/snapshots.ts b/x-pack/plugins/snapshot_restore/server/routes/api/snapshots.ts index 7307bad947211..fb68ca5c13dbe 100644 --- a/x-pack/plugins/snapshot_restore/server/routes/api/snapshots.ts +++ b/x-pack/plugins/snapshot_restore/server/routes/api/snapshots.ts @@ -37,6 +37,25 @@ export function registerSnapshotsRoutes({ // Silently swallow error as policy names aren't required in UI } + let repositories: string[] = []; + + try { + const { + body: repositoriesByName, + } = await clusterClient.asCurrentUser.snapshot.getRepository({ + repository: '_all', + }); + repositories = Object.keys(repositoriesByName); + + if (repositories.length === 0) { + return res.ok({ + body: { snapshots: [], repositories: [], policies }, + }); + } + } catch (e) { + return handleEsError({ error: e, response: res }); + } + try { // If any of these repositories 504 they will cost the request significant time. const { body: fetchedSnapshots } = await clusterClient.asCurrentUser.snapshot.get({ @@ -51,24 +70,16 @@ export function registerSnapshotsRoutes({ size: SNAPSHOT_LIST_MAX_SIZE, }); - const allRepos: string[] = []; - // Decorate each snapshot with the repository with which it's associated. const snapshots = fetchedSnapshots?.snapshots?.map((snapshot) => { - // @ts-expect-error @elastic/elasticsearch "repository" is a new field in the response - allRepos.push(snapshot.repository); return deserializeSnapshotDetails(snapshot as SnapshotDetailsEs, managedRepository); }); - const uniqueRepos = allRepos.filter((repo, index) => { - return allRepos.indexOf(repo) === index; - }); - return res.ok({ body: { snapshots: snapshots || [], policies, - repositories: uniqueRepos, + repositories, // @ts-expect-error @elastic/elasticsearch "failures" is a new field in the response errors: fetchedSnapshots?.failures, }, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 1709ee6b30665..5c5e99a40b257 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -17172,7 +17172,6 @@ "xpack.observability.notAvailable": "N/A", "xpack.observability.overview.alert.allTypes": "すべてのタイプ", "xpack.observability.overview.alert.appLink": "アラートを管理", - "xpack.observability.overview.alert.view": "表示", "xpack.observability.overview.alerts.muted": "ミュート", "xpack.observability.overview.alerts.title": "アラート", "xpack.observability.overview.apm.appLink": "アプリで表示", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 76d6ad2f903ad..e64d11b6dabc9 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -17408,7 +17408,6 @@ "xpack.observability.notAvailable": "不可用", "xpack.observability.overview.alert.allTypes": "所有类型", "xpack.observability.overview.alert.appLink": "管理告警", - "xpack.observability.overview.alert.view": "查看", "xpack.observability.overview.alerts.muted": "已静音", "xpack.observability.overview.alerts.title": "告警", "xpack.observability.overview.apm.appLink": "在应用中查看", diff --git a/x-pack/plugins/uptime/public/apps/render_app.tsx b/x-pack/plugins/uptime/public/apps/render_app.tsx index cb8c2e7203fe5..07119f985e738 100644 --- a/x-pack/plugins/uptime/public/apps/render_app.tsx +++ b/x-pack/plugins/uptime/public/apps/render_app.tsx @@ -59,7 +59,7 @@ export function renderApp( links: [ { linkType: 'documentation', - href: `${ELASTIC_WEBSITE_URL}guide/en/uptime/${DOC_LINK_VERSION}/uptime-app-overview.html`, + href: `${ELASTIC_WEBSITE_URL}guide/en/observability/${DOC_LINK_VERSION}/monitor-uptime.html`, }, { linkType: 'discuss', diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.test.ts b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.test.ts index 229933c2f0642..5f902095807d5 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.test.ts +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.test.ts @@ -206,6 +206,7 @@ describe('Palettes', () => { ssl: '#edc5a2', stylesheet: '#ca8eae', wait: '#b0c9e0', + xhr: '#e7664c', }); }); }); diff --git a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.ts b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.ts index 0f0ce01d25099..fa3db4d01fe9b 100644 --- a/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.ts +++ b/x-pack/plugins/uptime/public/components/monitor/synthetics/step_detail/waterfall/data_formatting.ts @@ -435,6 +435,7 @@ const buildMimeTypePalette = (): MimeTypeColourPalette => { case MimeType.Font: acc[value] = SAFE_PALETTE[8]; break; + case MimeType.XHR: case MimeType.Other: acc[value] = SAFE_PALETTE[9]; break; diff --git a/x-pack/plugins/uptime/public/lib/alert_types/duration_anomaly.tsx b/x-pack/plugins/uptime/public/lib/alert_types/duration_anomaly.tsx index 7ea28650d4885..a80e38ac622ad 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/duration_anomaly.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/duration_anomaly.tsx @@ -21,7 +21,7 @@ export const initDurationAnomalyAlertType: AlertTypeInitializer = ({ id: CLIENT_ALERT_TYPES.DURATION_ANOMALY, iconClass: 'uptimeApp', documentationUrl(docLinks) { - return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/uptime/${docLinks.DOC_LINK_VERSION}/uptime-alerting.html`; + return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/observability/${docLinks.DOC_LINK_VERSION}/duration-anomaly-alert.html`; }, alertParamsExpression: (params: unknown) => ( diff --git a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx index 3939fc06b49c8..50db7d9b5b5ad 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/monitor_status.tsx @@ -26,7 +26,7 @@ export const initMonitorStatusAlertType: AlertTypeInitializer = ({ description, iconClass: 'uptimeApp', documentationUrl(docLinks) { - return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/uptime/${docLinks.DOC_LINK_VERSION}/uptime-alerting.html#_monitor_status_alerts`; + return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/observability/${docLinks.DOC_LINK_VERSION}/monitor-status-alert.html`; }, alertParamsExpression: (params: any) => ( diff --git a/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx b/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx index 821f5bcad09d4..c3bcfc46646de 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/tls.tsx @@ -17,7 +17,7 @@ export const initTlsAlertType: AlertTypeInitializer = ({ core, plugins }): Alert id: CLIENT_ALERT_TYPES.TLS, iconClass: 'uptimeApp', documentationUrl(docLinks) { - return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/uptime/${docLinks.DOC_LINK_VERSION}/uptime-alerting.html#_tls_alerts`; + return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/observability/${docLinks.DOC_LINK_VERSION}/tls-certificate-alert.html`; }, alertParamsExpression: (params: any) => ( diff --git a/x-pack/plugins/uptime/public/lib/alert_types/tls_legacy.tsx b/x-pack/plugins/uptime/public/lib/alert_types/tls_legacy.tsx index 1abcdb2c98662..9982eb385d903 100644 --- a/x-pack/plugins/uptime/public/lib/alert_types/tls_legacy.tsx +++ b/x-pack/plugins/uptime/public/lib/alert_types/tls_legacy.tsx @@ -20,7 +20,7 @@ export const initTlsLegacyAlertType: AlertTypeInitializer = ({ id: CLIENT_ALERT_TYPES.TLS_LEGACY, iconClass: 'uptimeApp', documentationUrl(docLinks) { - return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/uptime/${docLinks.DOC_LINK_VERSION}/uptime-alerting.html#_tls_alerts`; + return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/observability/${docLinks.DOC_LINK_VERSION}/tls-certificate-alert.html`; }, alertParamsExpression: (params: any) => ( diff --git a/x-pack/test/apm_api_integration/tests/inspect/inspect.ts b/x-pack/test/apm_api_integration/tests/inspect/inspect.ts index 22623cb266203..77ceedaeb68b9 100644 --- a/x-pack/test/apm_api_integration/tests/inspect/inspect.ts +++ b/x-pack/test/apm_api_integration/tests/inspect/inspect.ts @@ -49,7 +49,7 @@ export default function customLinksTests({ getService }: FtrProviderContext) { }, }); expect(status).to.be(200); - expect(body._inspect?.length).to.be(1); + expect(body._inspect?.length).to.be(2); // @ts-expect-error expect(Object.keys(body._inspect[0])).to.eql([ diff --git a/x-pack/test/apm_api_integration/tests/observability_overview/observability_overview.ts b/x-pack/test/apm_api_integration/tests/observability_overview/observability_overview.ts index 746e746ccd827..99b18aca98a01 100644 --- a/x-pack/test/apm_api_integration/tests/observability_overview/observability_overview.ts +++ b/x-pack/test/apm_api_integration/tests/observability_overview/observability_overview.ts @@ -54,7 +54,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { expectSnapshot(response.body.serviceCount).toMatchInline(`9`); - expectSnapshot(response.body.transactionPerMinute.value).toMatchInline(`64.8`); + expectSnapshot(response.body.transactionPerMinute.value).toMatchInline(`41.4333333333333`); expectSnapshot(response.body.transactionPerMinute.timeseries.length).toMatchInline(`31`); expectSnapshot( @@ -68,23 +68,23 @@ export default function ApiTest({ getService }: FtrProviderContext) { Array [ Object { "x": "2020-12-08T13:57:00.000Z", - "y": 2, + "y": 10, }, Object { "x": "2020-12-08T13:58:00.000Z", - "y": 61, + "y": 43, }, Object { "x": "2020-12-08T13:59:00.000Z", - "y": 36, + "y": 18, }, Object { "x": "2020-12-08T14:00:00.000Z", - "y": 75, + "y": 57, }, Object { "x": "2020-12-08T14:01:00.000Z", - "y": 36, + "y": 15, }, ] `); diff --git a/x-pack/test/apm_api_integration/tests/service_overview/__snapshots__/instances_detailed_statistics.snap b/x-pack/test/apm_api_integration/tests/service_overview/__snapshots__/instances_detailed_statistics.snap index 99208e6cb466b..c3c9b95657c97 100644 --- a/x-pack/test/apm_api_integration/tests/service_overview/__snapshots__/instances_detailed_statistics.snap +++ b/x-pack/test/apm_api_integration/tests/service_overview/__snapshots__/instances_detailed_statistics.snap @@ -81,11 +81,11 @@ Object { }, Object { "x": 1607436840000, - "y": 0.333333333333333, + "y": 0.0833333333333333, }, Object { "x": 1607436900000, - "y": null, + "y": 0, }, Object { "x": 1607436960000, @@ -93,7 +93,7 @@ Object { }, Object { "x": 1607437020000, - "y": null, + "y": 0, }, Object { "x": 1607437080000, @@ -101,11 +101,11 @@ Object { }, Object { "x": 1607437140000, - "y": null, + "y": 0, }, Object { "x": 1607437200000, - "y": 0.333333333333333, + "y": 0.125, }, Object { "x": 1607437260000, @@ -113,19 +113,19 @@ Object { }, Object { "x": 1607437320000, - "y": 0.333333333333333, + "y": 0.166666666666667, }, Object { "x": 1607437380000, - "y": null, + "y": 0, }, Object { "x": 1607437440000, - "y": 0.5, + "y": 0.2, }, Object { "x": 1607437500000, - "y": null, + "y": 0, }, Object { "x": 1607437560000, @@ -143,11 +143,11 @@ Object { }, Object { "x": 1607436780000, - "y": 29997, + "y": 23071, }, Object { "x": 1607436840000, - "y": 48231, + "y": 48287, }, Object { "x": 1607436900000, @@ -155,7 +155,7 @@ Object { }, Object { "x": 1607436960000, - "y": 21973.8333333333, + "y": 22015, }, Object { "x": 1607437020000, @@ -163,7 +163,7 @@ Object { }, Object { "x": 1607437080000, - "y": 10142, + "y": 10159, }, Object { "x": 1607437140000, @@ -171,15 +171,15 @@ Object { }, Object { "x": 1607437200000, - "y": 28164.2222222222, + "y": 28258.5555555556, }, Object { "x": 1607437260000, - "y": 15968, + "y": 15999, }, Object { "x": 1607437320000, - "y": 17347.3333333333, + "y": 17407, }, Object { "x": 1607437380000, @@ -187,7 +187,7 @@ Object { }, Object { "x": 1607437440000, - "y": 11402.25, + "y": 11425, }, Object { "x": 1607437500000, @@ -195,7 +195,7 @@ Object { }, Object { "x": 1607437560000, - "y": 18157, + "y": 18175, }, Object { "x": 1607437620000, @@ -276,59 +276,59 @@ Object { }, Object { "x": 1607436780000, - "y": 1, + "y": 5, }, Object { "x": 1607436840000, - "y": 3, + "y": 12, }, Object { "x": 1607436900000, - "y": 0, + "y": 3, }, Object { "x": 1607436960000, - "y": 6, + "y": 13, }, Object { "x": 1607437020000, - "y": 0, + "y": 9, }, Object { "x": 1607437080000, - "y": 2, + "y": 5, }, Object { "x": 1607437140000, - "y": 0, + "y": 2, }, Object { "x": 1607437200000, - "y": 9, + "y": 16, }, Object { "x": 1607437260000, - "y": 1, + "y": 19, }, Object { "x": 1607437320000, - "y": 3, + "y": 6, }, Object { "x": 1607437380000, - "y": 0, + "y": 6, }, Object { "x": 1607437440000, - "y": 4, + "y": 10, }, Object { "x": 1607437500000, - "y": 0, + "y": 5, }, Object { "x": 1607437560000, - "y": 1, + "y": 4, }, Object { "x": 1607437620000, @@ -424,7 +424,7 @@ Object { }, Object { "x": 1607436960000, - "y": null, + "y": 0, }, Object { "x": 1607437020000, @@ -452,23 +452,23 @@ Object { }, Object { "x": 1607437380000, - "y": 0.142857142857143, + "y": 0.0769230769230769, }, Object { "x": 1607437440000, - "y": null, + "y": 0, }, Object { "x": 1607437500000, - "y": 0.222222222222222, + "y": 0.117647058823529, }, Object { "x": 1607437560000, - "y": null, + "y": 0, }, Object { "x": 1607437620000, - "y": 0.5, + "y": 0.25, }, ], "latency": Array [ @@ -478,15 +478,15 @@ Object { }, Object { "x": 1607436780000, - "y": 23426, + "y": 23491, }, Object { "x": 1607436840000, - "y": 8071285, + "y": 8093695, }, Object { "x": 1607436900000, - "y": 18416.75, + "y": 18463, }, Object { "x": 1607436960000, @@ -494,7 +494,7 @@ Object { }, Object { "x": 1607437020000, - "y": 23650.5, + "y": 23727, }, Object { "x": 1607437080000, @@ -502,15 +502,15 @@ Object { }, Object { "x": 1607437140000, - "y": 26507.6666666667, + "y": 26591, }, Object { "x": 1607437200000, - "y": 22211, + "y": 22271, }, Object { "x": 1607437260000, - "y": 11380.1666666667, + "y": 11404.3333333333, }, Object { "x": 1607437320000, @@ -518,7 +518,7 @@ Object { }, Object { "x": 1607437380000, - "y": 32408.5714285714, + "y": 32483.5714285714, }, Object { "x": 1607437440000, @@ -526,7 +526,7 @@ Object { }, Object { "x": 1607437500000, - "y": 15021, + "y": 15083.4444444444, }, Object { "x": 1607437560000, @@ -534,7 +534,7 @@ Object { }, Object { "x": 1607437620000, - "y": 36142.5, + "y": 56319, }, ], "memoryUsage": Array [ @@ -611,23 +611,23 @@ Object { }, Object { "x": 1607436780000, - "y": 4, + "y": 12, }, Object { "x": 1607436840000, - "y": 2, + "y": 4, }, Object { "x": 1607436900000, - "y": 4, + "y": 13, }, Object { "x": 1607436960000, - "y": 0, + "y": 3, }, Object { "x": 1607437020000, - "y": 4, + "y": 16, }, Object { "x": 1607437080000, @@ -635,7 +635,7 @@ Object { }, Object { "x": 1607437140000, - "y": 6, + "y": 11, }, Object { "x": 1607437200000, @@ -643,7 +643,7 @@ Object { }, Object { "x": 1607437260000, - "y": 6, + "y": 27, }, Object { "x": 1607437320000, @@ -651,23 +651,23 @@ Object { }, Object { "x": 1607437380000, - "y": 7, + "y": 13, }, Object { "x": 1607437440000, - "y": 0, + "y": 12, }, Object { "x": 1607437500000, - "y": 9, + "y": 17, }, Object { "x": 1607437560000, - "y": 0, + "y": 17, }, Object { "x": 1607437620000, - "y": 2, + "y": 4, }, ], }, @@ -824,7 +824,7 @@ Object { }, Object { "x": 1607436060000, - "y": null, + "y": 0, }, Object { "x": 1607436120000, @@ -852,23 +852,23 @@ Object { }, Object { "x": 1607436480000, - "y": 0.142857142857143, + "y": 0.0769230769230769, }, Object { "x": 1607436540000, - "y": null, + "y": 0, }, Object { "x": 1607436600000, - "y": 0.222222222222222, + "y": 0.117647058823529, }, Object { "x": 1607436660000, - "y": null, + "y": 0, }, Object { "x": 1607436720000, - "y": 0.5, + "y": 0.25, }, Object { "x": 1607436780000, @@ -876,11 +876,11 @@ Object { }, Object { "x": 1607436840000, - "y": 0.333333333333333, + "y": 0.0833333333333333, }, Object { "x": 1607436900000, - "y": null, + "y": 0, }, Object { "x": 1607436960000, @@ -888,7 +888,7 @@ Object { }, Object { "x": 1607437020000, - "y": null, + "y": 0, }, Object { "x": 1607437080000, @@ -896,11 +896,11 @@ Object { }, Object { "x": 1607437140000, - "y": null, + "y": 0, }, Object { "x": 1607437200000, - "y": 0.333333333333333, + "y": 0.125, }, Object { "x": 1607437260000, @@ -908,19 +908,19 @@ Object { }, Object { "x": 1607437320000, - "y": 0.333333333333333, + "y": 0.166666666666667, }, Object { "x": 1607437380000, - "y": null, + "y": 0, }, Object { "x": 1607437440000, - "y": 0.5, + "y": 0.2, }, Object { "x": 1607437500000, - "y": null, + "y": 0, }, Object { "x": 1607437560000, @@ -938,15 +938,15 @@ Object { }, Object { "x": 1607435880000, - "y": 23426, + "y": 23491, }, Object { "x": 1607435940000, - "y": 8071285, + "y": 8093695, }, Object { "x": 1607436000000, - "y": 18416.75, + "y": 18463, }, Object { "x": 1607436060000, @@ -954,7 +954,7 @@ Object { }, Object { "x": 1607436120000, - "y": 23650.5, + "y": 23727, }, Object { "x": 1607436180000, @@ -962,15 +962,15 @@ Object { }, Object { "x": 1607436240000, - "y": 26507.6666666667, + "y": 26591, }, Object { "x": 1607436300000, - "y": 22211, + "y": 22271, }, Object { "x": 1607436360000, - "y": 11380.1666666667, + "y": 11404.3333333333, }, Object { "x": 1607436420000, @@ -978,7 +978,7 @@ Object { }, Object { "x": 1607436480000, - "y": 32408.5714285714, + "y": 32483.5714285714, }, Object { "x": 1607436540000, @@ -986,7 +986,7 @@ Object { }, Object { "x": 1607436600000, - "y": 15021, + "y": 15083.4444444444, }, Object { "x": 1607436660000, @@ -994,15 +994,15 @@ Object { }, Object { "x": 1607436720000, - "y": 36142.5, + "y": 56319, }, Object { "x": 1607436780000, - "y": 29997, + "y": 23071, }, Object { "x": 1607436840000, - "y": 48231, + "y": 48287, }, Object { "x": 1607436900000, @@ -1010,7 +1010,7 @@ Object { }, Object { "x": 1607436960000, - "y": 21973.8333333333, + "y": 22015, }, Object { "x": 1607437020000, @@ -1018,7 +1018,7 @@ Object { }, Object { "x": 1607437080000, - "y": 10142, + "y": 10159, }, Object { "x": 1607437140000, @@ -1026,15 +1026,15 @@ Object { }, Object { "x": 1607437200000, - "y": 28164.2222222222, + "y": 28258.5555555556, }, Object { "x": 1607437260000, - "y": 15968, + "y": 15999, }, Object { "x": 1607437320000, - "y": 17347.3333333333, + "y": 17407, }, Object { "x": 1607437380000, @@ -1042,7 +1042,7 @@ Object { }, Object { "x": 1607437440000, - "y": 11402.25, + "y": 11425, }, Object { "x": 1607437500000, @@ -1050,7 +1050,7 @@ Object { }, Object { "x": 1607437560000, - "y": 18157, + "y": 18175, }, Object { "x": 1607437620000, @@ -1191,23 +1191,23 @@ Object { }, Object { "x": 1607435880000, - "y": 4, + "y": 12, }, Object { "x": 1607435940000, - "y": 2, + "y": 4, }, Object { "x": 1607436000000, - "y": 4, + "y": 13, }, Object { "x": 1607436060000, - "y": 0, + "y": 3, }, Object { "x": 1607436120000, - "y": 4, + "y": 16, }, Object { "x": 1607436180000, @@ -1215,7 +1215,7 @@ Object { }, Object { "x": 1607436240000, - "y": 6, + "y": 11, }, Object { "x": 1607436300000, @@ -1223,7 +1223,7 @@ Object { }, Object { "x": 1607436360000, - "y": 6, + "y": 27, }, Object { "x": 1607436420000, @@ -1231,79 +1231,79 @@ Object { }, Object { "x": 1607436480000, - "y": 7, + "y": 13, }, Object { "x": 1607436540000, - "y": 0, + "y": 12, }, Object { "x": 1607436600000, - "y": 9, + "y": 17, }, Object { "x": 1607436660000, - "y": 0, + "y": 17, }, Object { "x": 1607436720000, - "y": 2, + "y": 4, }, Object { "x": 1607436780000, - "y": 1, + "y": 5, }, Object { "x": 1607436840000, - "y": 3, + "y": 12, }, Object { "x": 1607436900000, - "y": 0, + "y": 3, }, Object { "x": 1607436960000, - "y": 6, + "y": 13, }, Object { "x": 1607437020000, - "y": 0, + "y": 9, }, Object { "x": 1607437080000, - "y": 2, + "y": 5, }, Object { "x": 1607437140000, - "y": 0, + "y": 2, }, Object { "x": 1607437200000, - "y": 9, + "y": 16, }, Object { "x": 1607437260000, - "y": 1, + "y": 19, }, Object { "x": 1607437320000, - "y": 3, + "y": 6, }, Object { "x": 1607437380000, - "y": 0, + "y": 6, }, Object { "x": 1607437440000, - "y": 4, + "y": 10, }, Object { "x": 1607437500000, - "y": 0, + "y": 5, }, Object { "x": 1607437560000, - "y": 1, + "y": 4, }, Object { "x": 1607437620000, diff --git a/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts b/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts index ee3966aa10a49..1149971f99e1d 100644 --- a/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts +++ b/x-pack/test/apm_api_integration/tests/service_overview/instance_details.ts @@ -31,7 +31,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { query: { start, end, - transactionType: 'request', }, }) ); @@ -61,7 +60,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { query: { start, end, - transactionType: 'request', }, }) ); @@ -89,7 +87,6 @@ export default function ApiTest({ getService }: FtrProviderContext) { query: { start, end, - transactionType: 'request', }, }) ); diff --git a/x-pack/test/apm_api_integration/tests/service_overview/instances_main_statistics.ts b/x-pack/test/apm_api_integration/tests/service_overview/instances_main_statistics.ts index f40ade6c4cfaf..53a1b43c72d17 100644 --- a/x-pack/test/apm_api_integration/tests/service_overview/instances_main_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/service_overview/instances_main_statistics.ts @@ -114,10 +114,10 @@ export default function ApiTest({ getService }: FtrProviderContext) { expectSnapshot(values).toMatchInline(` Object { "cpuUsage": 0.0120166666666667, - "errorRate": 0.16, - "latency": 237339.813333333, + "errorRate": 0.0415094339622641, + "latency": 237995.266666667, "memoryUsage": 0.941324615478516, - "throughput": 2.5, + "throughput": 8.83333333333333, } `); }); @@ -173,9 +173,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { expectSnapshot(values).toMatchInline(` Object { "cpuUsage": 0.00111666666666667, - "errorRate": 0.0373134328358209, - "latency": 70518.9328358209, - "throughput": 4.46666666666667, + "errorRate": 0.00963391136801541, + "latency": 71576.4545454545, + "throughput": 17.3, } `); @@ -260,10 +260,10 @@ export default function ApiTest({ getService }: FtrProviderContext) { expectSnapshot(values).toMatchInline(` Object { "cpuUsage": 0.0120666666666667, - "errorRate": 0.111111111111111, - "latency": 379742.555555556, + "errorRate": 0.0333333333333333, + "latency": 389086.636363636, "memoryUsage": 0.939879608154297, - "throughput": 3, + "throughput": 10, } `); }); diff --git a/x-pack/test/apm_api_integration/tests/services/__snapshots__/throughput.snap b/x-pack/test/apm_api_integration/tests/services/__snapshots__/throughput.snap index b4fd2219cb733..256a1450716f8 100644 --- a/x-pack/test/apm_api_integration/tests/services/__snapshots__/throughput.snap +++ b/x-pack/test/apm_api_integration/tests/services/__snapshots__/throughput.snap @@ -3,249 +3,129 @@ exports[`APM API tests basic apm_8.0.0 Throughput when data is loaded has the correct throughput 1`] = ` Array [ Object { - "x": 1607435850000, + "x": 1607435820000, "y": 0, }, Object { "x": 1607435880000, - "y": 8, - }, - Object { - "x": 1607435910000, - "y": 0, - }, - Object { - "x": 1607435940000, "y": 4, }, Object { - "x": 1607435970000, - "y": 0, + "x": 1607435940000, + "y": 1, }, Object { "x": 1607436000000, - "y": 6, - }, - Object { - "x": 1607436030000, - "y": 2, + "y": 4, }, Object { "x": 1607436060000, "y": 0, }, - Object { - "x": 1607436090000, - "y": 0, - }, Object { "x": 1607436120000, - "y": 8, - }, - Object { - "x": 1607436150000, - "y": 0, + "y": 4, }, Object { "x": 1607436180000, "y": 0, }, - Object { - "x": 1607436210000, - "y": 0, - }, Object { "x": 1607436240000, - "y": 12, - }, - Object { - "x": 1607436270000, - "y": 0, + "y": 3, }, Object { "x": 1607436300000, - "y": 0, - }, - Object { - "x": 1607436330000, - "y": 2, + "y": 1, }, Object { "x": 1607436360000, - "y": 10, - }, - Object { - "x": 1607436390000, - "y": 2, + "y": 6, }, Object { "x": 1607436420000, "y": 0, }, - Object { - "x": 1607436450000, - "y": 0, - }, Object { "x": 1607436480000, - "y": 4, - }, - Object { - "x": 1607436510000, - "y": 10, + "y": 7, }, Object { "x": 1607436540000, "y": 0, }, - Object { - "x": 1607436570000, - "y": 0, - }, Object { "x": 1607436600000, - "y": 4, - }, - Object { - "x": 1607436630000, - "y": 14, + "y": 9, }, Object { "x": 1607436660000, "y": 0, }, - Object { - "x": 1607436690000, - "y": 0, - }, Object { "x": 1607436720000, - "y": 0, - }, - Object { - "x": 1607436750000, - "y": 4, + "y": 1, }, Object { "x": 1607436780000, - "y": 0, - }, - Object { - "x": 1607436810000, "y": 2, }, Object { "x": 1607436840000, - "y": 2, - }, - Object { - "x": 1607436870000, - "y": 4, + "y": 3, }, Object { "x": 1607436900000, "y": 0, }, - Object { - "x": 1607436930000, - "y": 0, - }, Object { "x": 1607436960000, - "y": 4, - }, - Object { - "x": 1607436990000, - "y": 8, + "y": 6, }, Object { "x": 1607437020000, "y": 0, }, - Object { - "x": 1607437050000, - "y": 0, - }, Object { "x": 1607437080000, "y": 2, }, - Object { - "x": 1607437110000, - "y": 2, - }, Object { "x": 1607437140000, "y": 0, }, - Object { - "x": 1607437170000, - "y": 0, - }, Object { "x": 1607437200000, - "y": 4, - }, - Object { - "x": 1607437230000, - "y": 14, + "y": 7, }, Object { "x": 1607437260000, - "y": 2, - }, - Object { - "x": 1607437290000, - "y": 0, + "y": 1, }, Object { "x": 1607437320000, - "y": 2, - }, - Object { - "x": 1607437350000, - "y": 4, + "y": 3, }, Object { "x": 1607437380000, "y": 0, }, - Object { - "x": 1607437410000, - "y": 0, - }, Object { "x": 1607437440000, - "y": 2, - }, - Object { - "x": 1607437470000, - "y": 6, + "y": 4, }, Object { "x": 1607437500000, "y": 0, }, - Object { - "x": 1607437530000, - "y": 0, - }, Object { "x": 1607437560000, - "y": 2, - }, - Object { - "x": 1607437590000, - "y": 0, + "y": 1, }, Object { "x": 1607437620000, "y": 0, }, - Object { - "x": 1607437650000, - "y": 0, - }, ] `; @@ -253,734 +133,134 @@ exports[`APM API tests basic apm_8.0.0 Throughput when data is loaded with time Object { "currentPeriod": Array [ Object { - "x": 1607436770000, + "x": 1607436720000, "y": 0, }, Object { "x": 1607436780000, - "y": 0, - }, - Object { - "x": 1607436790000, - "y": 0, - }, - Object { - "x": 1607436800000, - "y": 0, - }, - Object { - "x": 1607436810000, - "y": 0, - }, - Object { - "x": 1607436820000, - "y": 6, - }, - Object { - "x": 1607436830000, - "y": 0, + "y": 2, }, Object { "x": 1607436840000, - "y": 0, - }, - Object { - "x": 1607436850000, - "y": 0, - }, - Object { - "x": 1607436860000, - "y": 6, - }, - Object { - "x": 1607436870000, - "y": 6, - }, - Object { - "x": 1607436880000, - "y": 6, - }, - Object { - "x": 1607436890000, - "y": 0, + "y": 3, }, Object { "x": 1607436900000, "y": 0, }, - Object { - "x": 1607436910000, - "y": 0, - }, - Object { - "x": 1607436920000, - "y": 0, - }, - Object { - "x": 1607436930000, - "y": 0, - }, - Object { - "x": 1607436940000, - "y": 0, - }, - Object { - "x": 1607436950000, - "y": 0, - }, Object { "x": 1607436960000, - "y": 0, - }, - Object { - "x": 1607436970000, - "y": 0, - }, - Object { - "x": 1607436980000, - "y": 12, - }, - Object { - "x": 1607436990000, "y": 6, }, - Object { - "x": 1607437000000, - "y": 18, - }, - Object { - "x": 1607437010000, - "y": 0, - }, Object { "x": 1607437020000, "y": 0, }, Object { - "x": 1607437030000, - "y": 0, - }, - Object { - "x": 1607437040000, - "y": 0, + "x": 1607437080000, + "y": 2, }, Object { - "x": 1607437050000, + "x": 1607437140000, "y": 0, }, Object { - "x": 1607437060000, - "y": 0, + "x": 1607437200000, + "y": 7, }, Object { - "x": 1607437070000, - "y": 0, + "x": 1607437260000, + "y": 1, }, Object { - "x": 1607437080000, - "y": 0, + "x": 1607437320000, + "y": 3, }, Object { - "x": 1607437090000, + "x": 1607437380000, "y": 0, }, Object { - "x": 1607437100000, - "y": 6, - }, - Object { - "x": 1607437110000, - "y": 6, + "x": 1607437440000, + "y": 4, }, Object { - "x": 1607437120000, + "x": 1607437500000, "y": 0, }, Object { - "x": 1607437130000, - "y": 0, + "x": 1607437560000, + "y": 1, }, Object { - "x": 1607437140000, + "x": 1607437620000, "y": 0, }, + ], + "previousPeriod": Array [ Object { - "x": 1607437150000, + "x": 1607436720000, "y": 0, }, Object { - "x": 1607437160000, - "y": 0, + "x": 1607436780000, + "y": 4, }, Object { - "x": 1607437170000, - "y": 0, + "x": 1607436840000, + "y": 1, }, Object { - "x": 1607437180000, - "y": 0, + "x": 1607436900000, + "y": 4, }, Object { - "x": 1607437190000, + "x": 1607436960000, "y": 0, }, Object { - "x": 1607437200000, - "y": 0, + "x": 1607437020000, + "y": 4, }, Object { - "x": 1607437210000, + "x": 1607437080000, "y": 0, }, Object { - "x": 1607437220000, - "y": 12, - }, - Object { - "x": 1607437230000, - "y": 30, - }, - Object { - "x": 1607437240000, - "y": 12, + "x": 1607437140000, + "y": 3, }, Object { - "x": 1607437250000, - "y": 0, + "x": 1607437200000, + "y": 1, }, Object { "x": 1607437260000, - "y": 0, - }, - Object { - "x": 1607437270000, "y": 6, }, - Object { - "x": 1607437280000, - "y": 0, - }, - Object { - "x": 1607437290000, - "y": 0, - }, - Object { - "x": 1607437300000, - "y": 0, - }, - Object { - "x": 1607437310000, - "y": 0, - }, Object { "x": 1607437320000, "y": 0, }, - Object { - "x": 1607437330000, - "y": 0, - }, - Object { - "x": 1607437340000, - "y": 6, - }, - Object { - "x": 1607437350000, - "y": 0, - }, - Object { - "x": 1607437360000, - "y": 12, - }, - Object { - "x": 1607437370000, - "y": 0, - }, Object { "x": 1607437380000, - "y": 0, - }, - Object { - "x": 1607437390000, - "y": 0, - }, - Object { - "x": 1607437400000, - "y": 0, - }, - Object { - "x": 1607437410000, - "y": 0, + "y": 7, }, Object { - "x": 1607437420000, - "y": 0, - }, - Object { - "x": 1607437430000, + "x": 1607437440000, "y": 0, }, Object { - "x": 1607437440000, - "y": 0, + "x": 1607437500000, + "y": 9, }, Object { - "x": 1607437450000, - "y": 0, - }, - Object { - "x": 1607437460000, - "y": 6, - }, - Object { - "x": 1607437470000, - "y": 12, - }, - Object { - "x": 1607437480000, - "y": 6, - }, - Object { - "x": 1607437490000, - "y": 0, - }, - Object { - "x": 1607437500000, - "y": 0, - }, - Object { - "x": 1607437510000, - "y": 0, - }, - Object { - "x": 1607437520000, - "y": 0, - }, - Object { - "x": 1607437530000, - "y": 0, - }, - Object { - "x": 1607437540000, - "y": 0, - }, - Object { - "x": 1607437550000, - "y": 0, - }, - Object { - "x": 1607437560000, - "y": 0, - }, - Object { - "x": 1607437570000, - "y": 6, - }, - Object { - "x": 1607437580000, - "y": 0, - }, - Object { - "x": 1607437590000, - "y": 0, - }, - Object { - "x": 1607437600000, - "y": 0, - }, - Object { - "x": 1607437610000, - "y": 0, - }, - Object { - "x": 1607437620000, - "y": 0, - }, - Object { - "x": 1607437630000, - "y": 0, - }, - Object { - "x": 1607437640000, - "y": 0, - }, - Object { - "x": 1607437650000, - "y": 0, - }, - Object { - "x": 1607437660000, - "y": 0, - }, - Object { - "x": 1607437670000, - "y": 0, - }, - ], - "previousPeriod": Array [ - Object { - "x": 1607436770000, - "y": 0, - }, - Object { - "x": 1607436780000, - "y": 0, - }, - Object { - "x": 1607436790000, - "y": 0, - }, - Object { - "x": 1607436800000, - "y": 24, - }, - Object { - "x": 1607436810000, - "y": 0, - }, - Object { - "x": 1607436820000, - "y": 0, - }, - Object { - "x": 1607436830000, - "y": 0, - }, - Object { - "x": 1607436840000, - "y": 12, - }, - Object { - "x": 1607436850000, - "y": 0, - }, - Object { - "x": 1607436860000, - "y": 0, - }, - Object { - "x": 1607436870000, - "y": 0, - }, - Object { - "x": 1607436880000, - "y": 0, - }, - Object { - "x": 1607436890000, - "y": 0, - }, - Object { - "x": 1607436900000, - "y": 0, - }, - Object { - "x": 1607436910000, - "y": 12, - }, - Object { - "x": 1607436920000, - "y": 6, - }, - Object { - "x": 1607436930000, - "y": 6, - }, - Object { - "x": 1607436940000, - "y": 0, - }, - Object { - "x": 1607436950000, - "y": 0, - }, - Object { - "x": 1607436960000, - "y": 0, - }, - Object { - "x": 1607436970000, - "y": 0, - }, - Object { - "x": 1607436980000, - "y": 0, - }, - Object { - "x": 1607436990000, - "y": 0, - }, - Object { - "x": 1607437000000, - "y": 0, - }, - Object { - "x": 1607437010000, - "y": 0, - }, - Object { - "x": 1607437020000, - "y": 0, - }, - Object { - "x": 1607437030000, - "y": 6, - }, - Object { - "x": 1607437040000, - "y": 18, - }, - Object { - "x": 1607437050000, - "y": 0, - }, - Object { - "x": 1607437060000, - "y": 0, - }, - Object { - "x": 1607437070000, - "y": 0, - }, - Object { - "x": 1607437080000, - "y": 0, - }, - Object { - "x": 1607437090000, - "y": 0, - }, - Object { - "x": 1607437100000, - "y": 0, - }, - Object { - "x": 1607437110000, - "y": 0, - }, - Object { - "x": 1607437120000, - "y": 0, - }, - Object { - "x": 1607437130000, - "y": 0, - }, - Object { - "x": 1607437140000, - "y": 0, - }, - Object { - "x": 1607437150000, - "y": 0, - }, - Object { - "x": 1607437160000, - "y": 36, - }, - Object { - "x": 1607437170000, - "y": 0, - }, - Object { - "x": 1607437180000, - "y": 0, - }, - Object { - "x": 1607437190000, - "y": 0, - }, - Object { - "x": 1607437200000, - "y": 0, - }, - Object { - "x": 1607437210000, - "y": 0, - }, - Object { - "x": 1607437220000, - "y": 0, - }, - Object { - "x": 1607437230000, - "y": 0, - }, - Object { - "x": 1607437240000, - "y": 6, - }, - Object { - "x": 1607437250000, - "y": 0, - }, - Object { - "x": 1607437260000, - "y": 0, - }, - Object { - "x": 1607437270000, - "y": 0, - }, - Object { - "x": 1607437280000, - "y": 30, - }, - Object { - "x": 1607437290000, - "y": 6, - }, - Object { - "x": 1607437300000, - "y": 0, - }, - Object { - "x": 1607437310000, - "y": 0, - }, - Object { - "x": 1607437320000, - "y": 0, - }, - Object { - "x": 1607437330000, - "y": 0, - }, - Object { - "x": 1607437340000, - "y": 0, - }, - Object { - "x": 1607437350000, - "y": 0, - }, - Object { - "x": 1607437360000, - "y": 0, - }, - Object { - "x": 1607437370000, - "y": 0, - }, - Object { - "x": 1607437380000, - "y": 0, - }, - Object { - "x": 1607437390000, - "y": 0, - }, - Object { - "x": 1607437400000, - "y": 12, - }, - Object { - "x": 1607437410000, - "y": 6, - }, - Object { - "x": 1607437420000, - "y": 24, - }, - Object { - "x": 1607437430000, - "y": 0, - }, - Object { - "x": 1607437440000, - "y": 0, - }, - Object { - "x": 1607437450000, - "y": 0, - }, - Object { - "x": 1607437460000, - "y": 0, - }, - Object { - "x": 1607437470000, - "y": 0, - }, - Object { - "x": 1607437480000, - "y": 0, - }, - Object { - "x": 1607437490000, - "y": 0, - }, - Object { - "x": 1607437500000, - "y": 0, - }, - Object { - "x": 1607437510000, - "y": 0, - }, - Object { - "x": 1607437520000, - "y": 12, - }, - Object { - "x": 1607437530000, - "y": 30, - }, - Object { - "x": 1607437540000, - "y": 12, - }, - Object { - "x": 1607437550000, - "y": 0, - }, - Object { - "x": 1607437560000, - "y": 0, - }, - Object { - "x": 1607437570000, - "y": 0, - }, - Object { - "x": 1607437580000, - "y": 0, - }, - Object { - "x": 1607437590000, - "y": 0, - }, - Object { - "x": 1607437600000, - "y": 0, - }, - Object { - "x": 1607437610000, + "x": 1607437560000, "y": 0, }, Object { "x": 1607437620000, - "y": 0, - }, - Object { - "x": 1607437630000, - "y": 0, - }, - Object { - "x": 1607437640000, - "y": 0, - }, - Object { - "x": 1607437650000, - "y": 6, - }, - Object { - "x": 1607437660000, - "y": 6, - }, - Object { - "x": 1607437670000, - "y": 0, + "y": 1, }, ], } diff --git a/x-pack/test/apm_api_integration/tests/services/throughput.ts b/x-pack/test/apm_api_integration/tests/services/throughput.ts index 4f568aafe33cc..e2cf9270d606d 100644 --- a/x-pack/test/apm_api_integration/tests/services/throughput.ts +++ b/x-pack/test/apm_api_integration/tests/services/throughput.ts @@ -68,17 +68,17 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('has the correct start date', () => { expectSnapshot( new Date(first(throughputResponse.currentPeriod)?.x ?? NaN).toISOString() - ).toMatchInline(`"2020-12-08T13:57:30.000Z"`); + ).toMatchInline(`"2020-12-08T13:57:00.000Z"`); }); it('has the correct end date', () => { expectSnapshot( new Date(last(throughputResponse.currentPeriod)?.x ?? NaN).toISOString() - ).toMatchInline(`"2020-12-08T14:27:30.000Z"`); + ).toMatchInline(`"2020-12-08T14:27:00.000Z"`); }); it('has the correct number of buckets', () => { - expectSnapshot(throughputResponse.currentPeriod.length).toMatchInline(`61`); + expectSnapshot(throughputResponse.currentPeriod.length).toMatchInline(`31`); }); it('has the correct throughput', () => { @@ -122,26 +122,26 @@ export default function ApiTest({ getService }: FtrProviderContext) { it('has the correct start date', () => { expectSnapshot( new Date(first(throughputResponse.currentPeriod)?.x ?? NaN).toISOString() - ).toMatchInline(`"2020-12-08T14:12:50.000Z"`); + ).toMatchInline(`"2020-12-08T14:12:00.000Z"`); expectSnapshot( new Date(first(throughputResponse.previousPeriod)?.x ?? NaN).toISOString() - ).toMatchInline(`"2020-12-08T14:12:50.000Z"`); + ).toMatchInline(`"2020-12-08T14:12:00.000Z"`); }); it('has the correct end date', () => { expectSnapshot( new Date(last(throughputResponse.currentPeriod)?.x ?? NaN).toISOString() - ).toMatchInline(`"2020-12-08T14:27:50.000Z"`); + ).toMatchInline(`"2020-12-08T14:27:00.000Z"`); expectSnapshot( new Date(last(throughputResponse.previousPeriod)?.x ?? NaN).toISOString() - ).toMatchInline(`"2020-12-08T14:27:50.000Z"`); + ).toMatchInline(`"2020-12-08T14:27:00.000Z"`); }); it('has the correct number of buckets', () => { - expectSnapshot(throughputResponse.currentPeriod.length).toMatchInline(`91`); - expectSnapshot(throughputResponse.previousPeriod.length).toMatchInline(`91`); + expectSnapshot(throughputResponse.currentPeriod.length).toMatchInline(`16`); + expectSnapshot(throughputResponse.previousPeriod.length).toMatchInline(`16`); }); it('has the correct throughput', () => { diff --git a/x-pack/test/apm_api_integration/tests/services/top_services.ts b/x-pack/test/apm_api_integration/tests/services/top_services.ts index 9c687fc74acce..3dc469790fe0c 100644 --- a/x-pack/test/apm_api_integration/tests/services/top_services.ts +++ b/x-pack/test/apm_api_integration/tests/services/top_services.ts @@ -98,18 +98,18 @@ export default function ApiTest({ getService }: FtrProviderContext) { Array [ Object { "avgResponseTime": Object { - "value": 420419.34550767, + "value": 421616.337243402, }, "transactionErrorRate": Object { "value": 0, }, "transactionsPerMinute": Object { - "value": 45.6333333333333, + "value": 25.2, }, }, Object { "avgResponseTime": Object { - "value": 2382833.33333333, + "value": 2387606.33333333, }, "transactionErrorRate": Object { "value": null, @@ -120,79 +120,79 @@ export default function ApiTest({ getService }: FtrProviderContext) { }, Object { "avgResponseTime": Object { - "value": 631521.83908046, + "value": 633386.908045977, }, "transactionErrorRate": Object { - "value": 0.0229885057471264, + "value": 0.027027027027027, }, "transactionsPerMinute": Object { - "value": 2.9, + "value": 2.46666666666667, }, }, Object { "avgResponseTime": Object { - "value": 27946.1484375, + "value": 27891.1507936508, }, "transactionErrorRate": Object { - "value": 0.015625, + "value": 0.0186915887850467, }, "transactionsPerMinute": Object { - "value": 4.26666666666667, + "value": 3.56666666666667, }, }, Object { "avgResponseTime": Object { - "value": 237339.813333333, + "value": 237995.266666667, }, "transactionErrorRate": Object { - "value": 0.16, + "value": 0.159420289855072, }, "transactionsPerMinute": Object { - "value": 2.5, + "value": 2.3, }, }, Object { "avgResponseTime": Object { - "value": 24920.1052631579, + "value": 24989.3157894737, }, "transactionErrorRate": Object { - "value": 0.0210526315789474, + "value": 0.0263157894736842, }, "transactionsPerMinute": Object { - "value": 3.16666666666667, + "value": 2.53333333333333, }, }, Object { "avgResponseTime": Object { - "value": 29542.6607142857, + "value": 29161.3703703704, }, "transactionErrorRate": Object { - "value": 0.0357142857142857, + "value": 0.0392156862745098, }, "transactionsPerMinute": Object { - "value": 1.86666666666667, + "value": 1.7, }, }, Object { "avgResponseTime": Object { - "value": 70518.9328358209, + "value": 71576.4545454545, }, "transactionErrorRate": Object { - "value": 0.0373134328358209, + "value": 0.0454545454545455, }, "transactionsPerMinute": Object { - "value": 4.46666666666667, + "value": 3.66666666666667, }, }, Object { "avgResponseTime": Object { - "value": 2319812.5, + "value": 2324991, }, "transactionErrorRate": Object { "value": null, }, "transactionsPerMinute": Object { - "value": 0.533333333333333, + "value": 0.5, }, }, ] @@ -329,18 +329,18 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(healthStatuses.filter(Boolean).length).to.be.greaterThan(0); expectSnapshot(healthStatuses).toMatchInline(` - Array [ - "healthy", - "healthy", - "healthy", - "healthy", - "healthy", - "healthy", - "healthy", - "healthy", - "healthy", - ] - `); + Array [ + "healthy", + "healthy", + "healthy", + "healthy", + "healthy", + "healthy", + "healthy", + "healthy", + "healthy", + ] + `); }); }); }); diff --git a/x-pack/test/apm_api_integration/tests/traces/__snapshots__/top_traces.snap b/x-pack/test/apm_api_integration/tests/traces/__snapshots__/top_traces.snap index ad9eca1cc0900..e77f50e8969b6 100644 --- a/x-pack/test/apm_api_integration/tests/traces/__snapshots__/top_traces.snap +++ b/x-pack/test/apm_api_integration/tests/traces/__snapshots__/top_traces.snap @@ -3,7 +3,7 @@ exports[`APM API tests basic apm_8.0.0 Top traces when data is loaded returns the correct buckets 1`] = ` Array [ Object { - "averageResponseTime": 1733, + "averageResponseTime": 1735, "impact": 0, "key": Object { "service.name": "opbeans-java", @@ -15,8 +15,8 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 8375, - "impact": 0.00305230364943525, + "averageResponseTime": 8383, + "impact": 0.0030743028761574, "key": Object { "service.name": "opbeans-java", "transaction.name": "APIRestController#product", @@ -27,8 +27,8 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 6469.33333333333, - "impact": 0.00812247320141043, + "averageResponseTime": 6495, + "impact": 0.00820831468889798, "key": Object { "service.name": "opbeans-python", "transaction.name": "GET opbeans.views.stats", @@ -39,8 +39,8 @@ Array [ "transactionsPerMinute": 0.1, }, Object { - "averageResponseTime": 19558, - "impact": 0.00819140508147898, + "averageResponseTime": 19583, + "impact": 0.00825363383478598, "key": Object { "service.name": "opbeans-python", "transaction.name": "GET opbeans.views.orders", @@ -51,8 +51,8 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 11083.5, - "impact": 0.00939036024880457, + "averageResponseTime": 11151, + "impact": 0.00951100891304591, "key": Object { "service.name": "opbeans-node", "transaction.name": "GET /api/products/:id", @@ -63,8 +63,8 @@ Array [ "transactionsPerMinute": 0.0666666666666667, }, Object { - "averageResponseTime": 3759.33333333333, - "impact": 0.00956912359111566, + "averageResponseTime": 3772.33333333333, + "impact": 0.00966453908074811, "key": Object { "service.name": "opbeans-java", "transaction.name": "ResourceHttpRequestHandler", @@ -75,8 +75,8 @@ Array [ "transactionsPerMinute": 0.2, }, Object { - "averageResponseTime": 5855.25, - "impact": 0.00996663076617762, + "averageResponseTime": 5873, + "impact": 0.0100613128274002, "key": Object { "service.name": "opbeans-go", "transaction.name": "GET /api/types/:id", @@ -87,32 +87,32 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 12828, - "impact": 0.010993715779199, + "averageResponseTime": 12847, + "impact": 0.0110796062890877, "key": Object { - "service.name": "opbeans-node", - "transaction.name": "GET /api/orders/:id", + "service.name": "opbeans-python", + "transaction.name": "GET opbeans.views.customer", }, - "serviceName": "opbeans-node", - "transactionName": "GET /api/orders/:id", + "serviceName": "opbeans-python", + "transactionName": "GET opbeans.views.customer", "transactionType": "request", "transactionsPerMinute": 0.0666666666666667, }, Object { - "averageResponseTime": 12835.5, - "impact": 0.0110006089672058, + "averageResponseTime": 12887, + "impact": 0.0111166015102208, "key": Object { - "service.name": "opbeans-python", - "transaction.name": "GET opbeans.views.customer", + "service.name": "opbeans-node", + "transaction.name": "GET /api/orders/:id", }, - "serviceName": "opbeans-python", - "transactionName": "GET opbeans.views.customer", + "serviceName": "opbeans-node", + "transactionName": "GET /api/orders/:id", "transactionType": "request", - "transactionsPerMinute": 0.0666666666666667, + "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 12892, - "impact": 0.0110525376501908, + "averageResponseTime": 12911, + "impact": 0.0111387986429006, "key": Object { "service.name": "opbeans-node", "transaction.name": "GET /api/types", @@ -123,8 +123,8 @@ Array [ "transactionsPerMinute": 0.0666666666666667, }, Object { - "averageResponseTime": 13052.5, - "impact": 0.0112000518735375, + "averageResponseTime": 13071, + "impact": 0.0112867795274328, "key": Object { "service.name": "opbeans-go", "transaction.name": "GET /api/types", @@ -132,11 +132,11 @@ Array [ "serviceName": "opbeans-go", "transactionName": "GET /api/types", "transactionType": "request", - "transactionsPerMinute": 0.0666666666666667, + "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 9224, - "impact": 0.0119201602473202, + "averageResponseTime": 9263, + "impact": 0.0120484186425097, "key": Object { "service.name": "opbeans-node", "transaction.name": "GET /api/products/top", @@ -147,8 +147,8 @@ Array [ "transactionsPerMinute": 0.1, }, Object { - "averageResponseTime": 29089, - "impact": 0.0125713367410344, + "averageResponseTime": 29183, + "impact": 0.0126930603707533, "key": Object { "service.name": "opbeans-python", "transaction.name": "GET opbeans.views.product_type", @@ -159,8 +159,8 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 15536.5, - "impact": 0.0134830757414078, + "averageResponseTime": 15551, + "impact": 0.0135804832376827, "key": Object { "service.name": "opbeans-python", "transaction.name": "GET opbeans.views.product", @@ -171,8 +171,8 @@ Array [ "transactionsPerMinute": 0.0666666666666667, }, Object { - "averageResponseTime": 11920.6666666667, - "impact": 0.0156378863123505, + "averageResponseTime": 11977.6666666667, + "impact": 0.0158145321538554, "key": Object { "service.name": "opbeans-ruby", "transaction.name": "Api::TypesController#index", @@ -183,8 +183,8 @@ Array [ "transactionsPerMinute": 0.1, }, Object { - "averageResponseTime": 18120.5, - "impact": 0.0158580087827027, + "averageResponseTime": 18175, + "impact": 0.0160073697440115, "key": Object { "service.name": "opbeans-ruby", "transaction.name": "Api::StatsController#index", @@ -195,8 +195,8 @@ Array [ "transactionsPerMinute": 0.0666666666666667, }, Object { - "averageResponseTime": 18420.5, - "impact": 0.0161337363029769, + "averageResponseTime": 18431, + "impact": 0.0162441391592631, "key": Object { "service.name": "opbeans-python", "transaction.name": "GET opbeans.views.product_types", @@ -207,8 +207,8 @@ Array [ "transactionsPerMinute": 0.0666666666666667, }, Object { - "averageResponseTime": 36843, - "impact": 0.0161346553947112, + "averageResponseTime": 36863, + "impact": 0.0162446015995272, "key": Object { "service.name": "opbeans-python", "transaction.name": "GET opbeans.views.product_customers", @@ -219,8 +219,8 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 6449.5, - "impact": 0.0169866534323584, + "averageResponseTime": 6471, + "impact": 0.0171523718380797, "key": Object { "service.name": "opbeans-go", "transaction.name": "GET /api/orders/:id", @@ -231,8 +231,8 @@ Array [ "transactionsPerMinute": 0.2, }, Object { - "averageResponseTime": 12930, - "impact": 0.0170293911980009, + "averageResponseTime": 12969.6666666667, + "impact": 0.0171907543800053, "key": Object { "service.name": "opbeans-java", "transaction.name": "APIRestController#topProducts", @@ -243,8 +243,8 @@ Array [ "transactionsPerMinute": 0.1, }, Object { - "averageResponseTime": 9985.5, - "impact": 0.0175587880369274, + "averageResponseTime": 10015, + "impact": 0.0177230231240572, "key": Object { "service.name": "opbeans-ruby", "transaction.name": "Api::TypesController#show", @@ -255,8 +255,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 8038.6, - "impact": 0.0176741340495754, + "averageResponseTime": 8055, + "impact": 0.0178224477808523, "key": Object { "service.name": "opbeans-go", "transaction.name": "GET /api/products", @@ -267,8 +267,8 @@ Array [ "transactionsPerMinute": 0.166666666666667, }, Object { - "averageResponseTime": 14898, - "impact": 0.0197425499974989, + "averageResponseTime": 14943, + "impact": 0.0199284007438518, "key": Object { "service.name": "opbeans-node", "transaction.name": "GET /api/products/:id/customers", @@ -279,8 +279,8 @@ Array [ "transactionsPerMinute": 0.1, }, Object { - "averageResponseTime": 15094.6666666667, - "impact": 0.0200136820591019, + "averageResponseTime": 15145.6666666667, + "impact": 0.0202095644244631, "key": Object { "service.name": "opbeans-ruby", "transaction.name": "Api::OrdersController#show", @@ -291,8 +291,8 @@ Array [ "transactionsPerMinute": 0.1, }, Object { - "averageResponseTime": 11634, - "impact": 0.0205890334847407, + "averageResponseTime": 11655, + "impact": 0.0207566312569682, "key": Object { "service.name": "opbeans-node", "transaction.name": "GET /api/products", @@ -300,11 +300,11 @@ Array [ "serviceName": "opbeans-node", "transactionName": "GET /api/products", "transactionType": "request", - "transactionsPerMinute": 0.133333333333333, + "transactionsPerMinute": 0.1, }, Object { - "averageResponseTime": 24650, - "impact": 0.0218592182614704, + "averageResponseTime": 24703, + "impact": 0.0220449898329271, "key": Object { "service.name": "opbeans-python", "transaction.name": "GET opbeans.views.customers", @@ -315,8 +315,8 @@ Array [ "transactionsPerMinute": 0.0666666666666667, }, Object { - "averageResponseTime": 12336.25, - "impact": 0.021879897825491, + "averageResponseTime": 12367, + "impact": 0.0220736611293052, "key": Object { "service.name": "opbeans-ruby", "transaction.name": "Api::ProductsController#show", @@ -327,8 +327,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 5010, - "impact": 0.0222268549551693, + "averageResponseTime": 5019.8, + "impact": 0.0224112425221444, "key": Object { "service.name": "kibana", "transaction.name": "GET /translations/?.json", @@ -336,11 +336,11 @@ Array [ "serviceName": "kibana", "transactionName": "GET /translations/?.json", "transactionType": "request", - "transactionsPerMinute": 0.333333333333333, + "transactionsPerMinute": 0.3, }, Object { - "averageResponseTime": 8931.66666666667, - "impact": 0.0238306700314309, + "averageResponseTime": 8964.33333333333, + "impact": 0.0240704781899622, "key": Object { "service.name": "opbeans-python", "transaction.name": "GET opbeans.views.order", @@ -351,8 +351,8 @@ Array [ "transactionsPerMinute": 0.2, }, Object { - "averageResponseTime": 14941.75, - "impact": 0.0266692848526536, + "averageResponseTime": 14959, + "impact": 0.02686824178815, "key": Object { "service.name": "opbeans-node", "transaction.name": "GET /api/types/:id", @@ -363,8 +363,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 15228, - "impact": 0.0271954648705102, + "averageResponseTime": 15279, + "impact": 0.0274601653262789, "key": Object { "service.name": "opbeans-ruby", "transaction.name": "Api::ProductsController#index", @@ -375,8 +375,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 20579, - "impact": 0.0275745902108872, + "averageResponseTime": 20639, + "impact": 0.0278305799778737, "key": Object { "service.name": "opbeans-java", "transaction.name": "APIRestController#orders", @@ -387,8 +387,8 @@ Array [ "transactionsPerMinute": 0.1, }, Object { - "averageResponseTime": 21196.3333333333, - "impact": 0.0284256691568002, + "averageResponseTime": 21247, + "impact": 0.0286740710197075, "key": Object { "service.name": "opbeans-node", "transaction.name": "GET /api/stats", @@ -399,8 +399,8 @@ Array [ "transactionsPerMinute": 0.1, }, Object { - "averageResponseTime": 7676.55555555556, - "impact": 0.0309531714259802, + "averageResponseTime": 7703, + "impact": 0.0312572623353235, "key": Object { "service.name": "opbeans-go", "transaction.name": "GET /api/customers/:id", @@ -408,11 +408,11 @@ Array [ "serviceName": "opbeans-go", "transactionName": "GET /api/customers/:id", "transactionType": "request", - "transactionsPerMinute": 0.3, + "transactionsPerMinute": 0.233333333333333, }, Object { - "averageResponseTime": 17371.25, - "impact": 0.0311351515893612, + "averageResponseTime": 17391, + "impact": 0.0313668606779302, "key": Object { "service.name": "opbeans-node", "transaction.name": "GET /api/orders", @@ -423,8 +423,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 13335.1666666667, - "impact": 0.0359723313867047, + "averageResponseTime": 13380.3333333333, + "impact": 0.0363232954292321, "key": Object { "service.name": "opbeans-java", "transaction.name": "APIRestController#customerWhoBought", @@ -435,8 +435,8 @@ Array [ "transactionsPerMinute": 0.2, }, Object { - "averageResponseTime": 14484.5, - "impact": 0.0391413596863894, + "averageResponseTime": 14516.3333333333, + "impact": 0.0394752882697689, "key": Object { "service.name": "opbeans-java", "transaction.name": "APIRestController#customer", @@ -444,11 +444,11 @@ Array [ "serviceName": "opbeans-java", "transactionName": "APIRestController#customer", "transactionType": "request", - "transactionsPerMinute": 0.2, + "transactionsPerMinute": 0.166666666666667, }, Object { - "averageResponseTime": 24357.75, - "impact": 0.0439776203919986, + "averageResponseTime": 24439, + "impact": 0.044403976605221, "key": Object { "service.name": "opbeans-node", "transaction.name": "GET /api/customers/:id", @@ -459,8 +459,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 12406.125, - "impact": 0.0448130747784294, + "averageResponseTime": 12435, + "impact": 0.0452012236206385, "key": Object { "service.name": "opbeans-go", "transaction.name": "GET /api/orders", @@ -471,8 +471,8 @@ Array [ "transactionsPerMinute": 0.266666666666667, }, Object { - "averageResponseTime": 21325.6, - "impact": 0.0482040637319348, + "averageResponseTime": 21362.2, + "impact": 0.0485913731972194, "key": Object { "service.name": "opbeans-ruby", "transaction.name": "Api::ProductsController#top", @@ -483,8 +483,8 @@ Array [ "transactionsPerMinute": 0.166666666666667, }, Object { - "averageResponseTime": 18433.3333333333, - "impact": 0.0500293799161499, + "averageResponseTime": 18473.6666666667, + "impact": 0.0504554699020615, "key": Object { "service.name": "opbeans-ruby", "transaction.name": "Api::CustomersController#show", @@ -495,8 +495,8 @@ Array [ "transactionsPerMinute": 0.2, }, Object { - "averageResponseTime": 17494.875, - "impact": 0.063521187029033, + "averageResponseTime": 17531, + "impact": 0.0640539883100466, "key": Object { "service.name": "opbeans-java", "transaction.name": "APIRestController#order", @@ -507,8 +507,8 @@ Array [ "transactionsPerMinute": 0.266666666666667, }, Object { - "averageResponseTime": 142785, - "impact": 0.0648198636495244, + "averageResponseTime": 143359, + "impact": 0.0654926399718585, "key": Object { "service.name": "kibana", "transaction.name": "taskManager markTaskAsRunning apm-telemetry-task", @@ -519,8 +519,8 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 14967, - "impact": 0.0748618599379103, + "averageResponseTime": 15001.1818181818, + "impact": 0.0755063214520499, "key": Object { "service.name": "opbeans-ruby", "transaction.name": "Api::CustomersController#index", @@ -528,11 +528,11 @@ Array [ "serviceName": "opbeans-ruby", "transactionName": "Api::CustomersController#index", "transactionType": "request", - "transactionsPerMinute": 0.366666666666667, + "transactionsPerMinute": 0.3, }, Object { - "averageResponseTime": 33210.8, - "impact": 0.0755130364316245, + "averageResponseTime": 33330.2, + "impact": 0.0762637986047493, "key": Object { "service.name": "opbeans-node", "transaction.name": "GET /api/customers", @@ -540,11 +540,11 @@ Array [ "serviceName": "opbeans-node", "transactionName": "GET /api/customers", "transactionType": "request", - "transactionsPerMinute": 0.166666666666667, + "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 34083.6, - "impact": 0.0775184945957521, + "averageResponseTime": 34226.2, + "impact": 0.0783355309882007, "key": Object { "service.name": "opbeans-ruby", "transaction.name": "Api::OrdersController#index", @@ -555,8 +555,8 @@ Array [ "transactionsPerMinute": 0.166666666666667, }, Object { - "averageResponseTime": 21461.4444444444, - "impact": 0.0879662698848082, + "averageResponseTime": 21549.2222222222, + "impact": 0.0888847182942931, "key": Object { "service.name": "opbeans-go", "transaction.name": "GET /api/customers", @@ -564,11 +564,11 @@ Array [ "serviceName": "opbeans-go", "transactionName": "GET /api/customers", "transactionType": "request", - "transactionsPerMinute": 0.3, + "transactionsPerMinute": 0.266666666666667, }, Object { - "averageResponseTime": 48180.4, - "impact": 0.109909125494095, + "averageResponseTime": 48267.8, + "impact": 0.110802537054575, "key": Object { "service.name": "opbeans-java", "transaction.name": "APIRestController#customers", @@ -579,8 +579,8 @@ Array [ "transactionsPerMinute": 0.166666666666667, }, Object { - "averageResponseTime": 42987.1666666667, - "impact": 0.117731055698407, + "averageResponseTime": 43113, + "impact": 0.118820788794902, "key": Object { "service.name": "opbeans-go", "transaction.name": "GET /api/stats", @@ -588,11 +588,11 @@ Array [ "serviceName": "opbeans-go", "transactionName": "GET /api/stats", "transactionType": "request", - "transactionsPerMinute": 0.2, + "transactionsPerMinute": 0.166666666666667, }, Object { - "averageResponseTime": 28776, - "impact": 0.131442525735775, + "averageResponseTime": 28824.6, + "impact": 0.132494222525682, "key": Object { "service.name": "kibana", "transaction.name": "GET /node_modules/@kbn/ui-framework/dist/#", @@ -603,8 +603,8 @@ Array [ "transactionsPerMinute": 0.333333333333333, }, Object { - "averageResponseTime": 92744.75, - "impact": 0.169685473251938, + "averageResponseTime": 93055, + "impact": 0.171327181268528, "key": Object { "service.name": "kibana", "transaction.name": "GET /internal/security/session", @@ -615,8 +615,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 93108.25, - "impact": 0.170353652942735, + "averageResponseTime": 93439, + "impact": 0.172037489514283, "key": Object { "service.name": "kibana", "transaction.name": "GET /api/licensing/info", @@ -627,8 +627,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 95624.75, - "impact": 0.174979441641202, + "averageResponseTime": 95871, + "impact": 0.176536108404063, "key": Object { "service.name": "kibana", "transaction.name": "POST /internal/licensing/feature_usage/register", @@ -639,8 +639,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 96539, - "impact": 0.176660000877273, + "averageResponseTime": 96767, + "impact": 0.178193494310824, "key": Object { "service.name": "kibana", "transaction.name": "GET /internal/security_oss/display_insecure_cluster_alert", @@ -651,8 +651,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 88800, - "impact": 0.203241972015173, + "averageResponseTime": 89087, + "impact": 0.205184745209241, "key": Object { "service.name": "kibana-frontend", "transaction.name": "POST /internal/licensing/feature_usage/register", @@ -660,11 +660,11 @@ Array [ "serviceName": "kibana-frontend", "transactionName": "POST /internal/licensing/feature_usage/register", "transactionType": "http-request", - "transactionsPerMinute": 0.166666666666667, + "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 37402.25, - "impact": 0.205460199915779, + "averageResponseTime": 37503, + "impact": 0.207312432864657, "key": Object { "service.name": "opbeans-java", "transaction.name": "DispatcherServlet#doGet", @@ -672,11 +672,11 @@ Array [ "serviceName": "opbeans-java", "transactionName": "DispatcherServlet#doGet", "transactionType": "request", - "transactionsPerMinute": 0.4, + "transactionsPerMinute": 0.3, }, Object { - "averageResponseTime": 43016.8181818182, - "impact": 0.216653818147177, + "averageResponseTime": 43191, + "impact": 0.218903498085909, "key": Object { "service.name": "opbeans-go", "transaction.name": "GET /api/products/:id", @@ -684,11 +684,11 @@ Array [ "serviceName": "opbeans-go", "transactionName": "GET /api/products/:id", "transactionType": "request", - "transactionsPerMinute": 0.366666666666667, + "transactionsPerMinute": 0.266666666666667, }, Object { - "averageResponseTime": 43420.8181818182, - "impact": 0.218696039980674, + "averageResponseTime": 43542.2727272727, + "impact": 0.220690367266636, "key": Object { "service.name": "kibana", "transaction.name": "GET /38640/bundles/plugin/ml/#", @@ -696,11 +696,11 @@ Array [ "serviceName": "kibana", "transactionName": "GET /38640/bundles/plugin/ml/#", "transactionType": "request", - "transactionsPerMinute": 0.366666666666667, + "transactionsPerMinute": 0.0666666666666667, }, Object { - "averageResponseTime": 43882.8571428571, - "impact": 0.281530205938357, + "averageResponseTime": 43953.2857142857, + "impact": 0.283758432933486, "key": Object { "service.name": "opbeans-go", "transaction.name": "GET /api/products/:id/customers", @@ -708,11 +708,11 @@ Array [ "serviceName": "opbeans-go", "transactionName": "GET /api/products/:id/customers", "transactionType": "request", - "transactionsPerMinute": 0.466666666666667, + "transactionsPerMinute": 0.433333333333333, }, Object { - "averageResponseTime": 102547.833333333, - "impact": 0.281956204957181, + "averageResponseTime": 102740.333333333, + "impact": 0.284265267463009, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run alerts_invalidate_api_keys", @@ -723,8 +723,8 @@ Array [ "transactionsPerMinute": 0.2, }, Object { - "averageResponseTime": 90847, - "impact": 0.333190514136929, + "averageResponseTime": 91135, + "impact": 0.336353613937831, "key": Object { "service.name": "kibana", "transaction.name": "GET /internal/security/me", @@ -732,11 +732,11 @@ Array [ "serviceName": "kibana", "transactionName": "GET /internal/security/me", "transactionType": "request", - "transactionsPerMinute": 0.266666666666667, + "transactionsPerMinute": 0.2, }, Object { - "averageResponseTime": 37214.1739130435, - "impact": 0.392540862875948, + "averageResponseTime": 37317.9565217391, + "impact": 0.396116156596443, "key": Object { "service.name": "opbeans-node", "transaction.name": "GET /api", @@ -744,11 +744,11 @@ Array [ "serviceName": "opbeans-node", "transactionName": "GET /api", "transactionType": "request", - "transactionsPerMinute": 0.766666666666667, + "transactionsPerMinute": 0.5, }, Object { - "averageResponseTime": 146027.666666667, - "impact": 0.40184207122653, + "averageResponseTime": 146772.333333333, + "impact": 0.406438285732831, "key": Object { "service.name": "kibana", "transaction.name": "taskManager markTaskAsRunning alerts_invalidate_api_keys", @@ -759,8 +759,8 @@ Array [ "transactionsPerMinute": 0.2, }, Object { - "averageResponseTime": 268399, - "impact": 0.492570211772752, + "averageResponseTime": 269823, + "impact": 0.498305743730977, "key": Object { "service.name": "kibana", "transaction.name": "GET /api/spaces/space", @@ -771,8 +771,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 268724.75, - "impact": 0.493169000037614, + "averageResponseTime": 269823, + "impact": 0.498305743730977, "key": Object { "service.name": "kibana", "transaction.name": "GET /api/saved_objects_tagging/tags", @@ -783,8 +783,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 269158, - "impact": 0.493965393025339, + "averageResponseTime": 270335, + "impact": 0.499252821391983, "key": Object { "service.name": "kibana", "transaction.name": "GET /internal/spaces/_active_space", @@ -795,8 +795,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 1095000, - "impact": 0.502406331512666, + "averageResponseTime": 1097727, + "impact": 0.506830830000827, "key": Object { "service.name": "kibana-frontend", "transaction.name": "GET /internal/security/me", @@ -807,8 +807,8 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 267886.8, - "impact": 0.614734965997167, + "averageResponseTime": 269515.8, + "impact": 0.622372454882547, "key": Object { "service.name": "kibana", "transaction.name": "GET /spaces/enter", @@ -819,8 +819,8 @@ Array [ "transactionsPerMinute": 0.166666666666667, }, Object { - "averageResponseTime": 1440000, - "impact": 0.660949655670324, + "averageResponseTime": 1441791, + "impact": 0.665939877049897, "key": Object { "service.name": "kibana-frontend", "transaction.name": "GET /api/ml/ml_capabilities", @@ -831,8 +831,8 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 27651.6981132075, - "impact": 0.672686457116662, + "averageResponseTime": 27717.641509434, + "impact": 0.678538599606761, "key": Object { "service.name": "kibana", "transaction.name": "GET /ui/#", @@ -840,11 +840,11 @@ Array [ "serviceName": "kibana", "transactionName": "GET /ui/#", "transactionType": "request", - "transactionsPerMinute": 1.76666666666667, + "transactionsPerMinute": 0.566666666666667, }, Object { - "averageResponseTime": 1482000, - "impact": 0.680250582089517, + "averageResponseTime": 1482751, + "impact": 0.684881430270024, "key": Object { "service.name": "kibana-frontend", "transaction.name": "POST /api/ml/jobs/jobs", @@ -855,20 +855,20 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 755000, - "impact": 0.693117866368979, + "averageResponseTime": 756175, + "impact": 0.698569199648993, "key": Object { "service.name": "kibana-frontend", "transaction.name": "/app/ml", }, "serviceName": "kibana-frontend", "transactionName": "/app/ml", - "transactionType": "route-change", + "transactionType": "page-load", "transactionsPerMinute": 0.0666666666666667, }, Object { - "averageResponseTime": 1685000, - "impact": 0.773538393115617, + "averageResponseTime": 1687551, + "impact": 0.779589196370662, "key": Object { "service.name": "kibana-frontend", "transaction.name": "/app/ml/*?{query}", @@ -879,8 +879,8 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 958000, - "impact": 0.879693488421179, + "averageResponseTime": 960511, + "impact": 0.887555587285124, "key": Object { "service.name": "opbeans-rum", "transaction.name": "/customers", @@ -891,8 +891,8 @@ Array [ "transactionsPerMinute": 0.0666666666666667, }, Object { - "averageResponseTime": 32154.8666666667, - "impact": 0.885801772086987, + "averageResponseTime": 32237.9333333333, + "impact": 0.893684770546344, "key": Object { "service.name": "opbeans-python", "transaction.name": "opbeans.tasks.sync_orders", @@ -900,11 +900,11 @@ Array [ "serviceName": "opbeans-python", "transactionName": "opbeans.tasks.sync_orders", "transactionType": "celery", - "transactionsPerMinute": 2, + "transactionsPerMinute": 1.53333333333333, }, Object { - "averageResponseTime": 789635, - "impact": 1.08782410937081, + "averageResponseTime": 791892.333333333, + "impact": 1.09780636558827, "key": Object { "service.name": "kibana", "transaction.name": "POST /api/ui_counters/_report", @@ -915,8 +915,8 @@ Array [ "transactionsPerMinute": 0.1, }, Object { - "averageResponseTime": 93174.5862068966, - "impact": 1.24092549136999, + "averageResponseTime": 93253.6206896552, + "impact": 1.24980030673293, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run endpoint:user-artifact-packager", @@ -927,8 +927,8 @@ Array [ "transactionsPerMinute": 0.966666666666667, }, Object { - "averageResponseTime": 697220.5, - "impact": 1.2808228040078, + "averageResponseTime": 699391, + "impact": 1.29290390131532, "key": Object { "service.name": "kibana", "transaction.name": "POST /api/core/capabilities", @@ -939,8 +939,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 285854.3, - "impact": 1.3128352286575, + "averageResponseTime": 286719, + "impact": 1.32510176714795, "key": Object { "service.name": "kibana", "transaction.name": "GET /bootstrap.js", @@ -951,8 +951,8 @@ Array [ "transactionsPerMinute": 0.333333333333333, }, Object { - "averageResponseTime": 1453500, - "impact": 1.33510344274071, + "averageResponseTime": 1458175, + "impact": 1.34783533053422, "key": Object { "service.name": "kibana-frontend", "transaction.name": "GET /api/apm/services/kibana/transactions/groups/overview", @@ -963,8 +963,8 @@ Array [ "transactionsPerMinute": 0.0666666666666667, }, Object { - "averageResponseTime": 81613.5, - "impact": 1.34938888556612, + "averageResponseTime": 81863, + "impact": 1.36204057056879, "key": Object { "service.name": "kibana", "transaction.name": "GET /plugins/kibanaOverview/assets/#", @@ -972,11 +972,11 @@ Array [ "serviceName": "kibana", "transactionName": "GET /plugins/kibanaOverview/assets/#", "transactionType": "request", - "transactionsPerMinute": 1.2, + "transactionsPerMinute": 0.266666666666667, }, Object { - "averageResponseTime": 3128000, - "impact": 1.43666307937504, + "averageResponseTime": 3129343, + "impact": 1.44633186971915, "key": Object { "service.name": "kibana-frontend", "transaction.name": "/services/:serviceName/transactions", @@ -987,8 +987,8 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 1606500, - "impact": 1.47572447808055, + "averageResponseTime": 1609983, + "impact": 1.48823959377841, "key": Object { "service.name": "kibana-frontend", "transaction.name": "/app/dev_tools", @@ -999,8 +999,8 @@ Array [ "transactionsPerMinute": 0.0666666666666667, }, Object { - "averageResponseTime": 1190000, - "impact": 1.63978235264369, + "averageResponseTime": 1193300.33333333, + "impact": 1.65468803026002, "key": Object { "service.name": "kibana-frontend", "transaction.name": "/app/kibanaOverview", @@ -1011,8 +1011,8 @@ Array [ "transactionsPerMinute": 0.1, }, Object { - "averageResponseTime": 144634.586206897, - "impact": 1.92672417071329, + "averageResponseTime": 145265.75862069, + "impact": 1.94732300406412, "key": Object { "service.name": "kibana", "transaction.name": "taskManager markTaskAsRunning endpoint:user-artifact-packager", @@ -1023,8 +1023,8 @@ Array [ "transactionsPerMinute": 0.966666666666667, }, Object { - "averageResponseTime": 757333.333333333, - "impact": 2.08738002722212, + "averageResponseTime": 759124.333333333, + "impact": 2.10549560957826, "key": Object { "service.name": "opbeans-rum", "transaction.name": "/dashboard", @@ -1032,11 +1032,11 @@ Array [ "serviceName": "opbeans-rum", "transactionName": "/dashboard", "transactionType": "page-load", - "transactionsPerMinute": 0.2, + "transactionsPerMinute": 0.166666666666667, }, Object { - "averageResponseTime": 5142000, - "impact": 2.36218845576206, + "averageResponseTime": 5144575, + "impact": 2.37825628814941, "key": Object { "service.name": "kibana-frontend", "transaction.name": "/app/observability-overview", @@ -1047,8 +1047,8 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 1496250, - "impact": 2.74958562174729, + "averageResponseTime": 1501183, + "impact": 2.7760275184513, "key": Object { "service.name": "kibana-frontend", "transaction.name": "POST /api/ml/jobs/jobs_summary", @@ -1056,11 +1056,11 @@ Array [ "serviceName": "kibana-frontend", "transactionName": "POST /api/ml/jobs/jobs_summary", "transactionType": "http-request", - "transactionsPerMinute": 0.133333333333333, + "transactionsPerMinute": 0.1, }, Object { - "averageResponseTime": 6675000, - "impact": 3.06667227006261, + "averageResponseTime": 6684671, + "impact": 3.0904586892262, "key": Object { "service.name": "kibana-frontend", "transaction.name": "/services/:serviceName/overview", @@ -1071,8 +1071,8 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 213841.46875, - "impact": 3.14384242889108, + "averageResponseTime": 214655, + "impact": 3.17568134306859, "key": Object { "service.name": "opbeans-ruby", "transaction.name": "Rack", @@ -1080,11 +1080,11 @@ Array [ "serviceName": "opbeans-ruby", "transactionName": "Rack", "transactionType": "request", - "transactionsPerMinute": 1.06666666666667, + "transactionsPerMinute": 0.633333333333333, }, Object { - "averageResponseTime": 6913000, - "impact": 3.17604418643803, + "averageResponseTime": 6914047, + "impact": 3.19653138725892, "key": Object { "service.name": "kibana-frontend", "transaction.name": "POST /api/ml/jobs/force_start_datafeeds", @@ -1095,8 +1095,8 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 1948000, - "impact": 3.57998500363972, + "averageResponseTime": 1953791, + "impact": 3.61324417078093, "key": Object { "service.name": "opbeans-rum", "transaction.name": "/products", @@ -1107,8 +1107,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 145833.571428571, - "impact": 3.75216764913361, + "averageResponseTime": 146412.037037037, + "impact": 3.6553660046825, "key": Object { "service.name": "kibana", "transaction.name": "taskManager markTaskAsRunning alerting:monitoring_alert_elasticsearch_version_mismatch", @@ -1116,11 +1116,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager markTaskAsRunning alerting:monitoring_alert_elasticsearch_version_mismatch", "transactionType": "taskManager", - "transactionsPerMinute": 1.86666666666667, + "transactionsPerMinute": 1.23333333333333, }, Object { - "averageResponseTime": 145835.785714286, - "impact": 3.75222463282113, + "averageResponseTime": 146412.037037037, + "impact": 3.6553660046825, "key": Object { "service.name": "kibana", "transaction.name": "taskManager markTaskAsRunning alerting:monitoring_alert_cpu_usage", @@ -1128,11 +1128,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager markTaskAsRunning alerting:monitoring_alert_cpu_usage", "transactionType": "taskManager", - "transactionsPerMinute": 1.86666666666667, + "transactionsPerMinute": 1.23333333333333, }, Object { - "averageResponseTime": 149008.25, - "impact": 3.83386663248258, + "averageResponseTime": 149692.62962963, + "impact": 3.73728822235955, "key": Object { "service.name": "kibana", "transaction.name": "taskManager markTaskAsRunning alerting:monitoring_alert_license_expiration", @@ -1140,11 +1140,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager markTaskAsRunning alerting:monitoring_alert_license_expiration", "transactionType": "taskManager", - "transactionsPerMinute": 1.86666666666667, + "transactionsPerMinute": 1.16666666666667, }, Object { - "averageResponseTime": 149012.642857143, - "impact": 3.83397968076589, + "averageResponseTime": 149692.62962963, + "impact": 3.73728822235955, "key": Object { "service.name": "kibana", "transaction.name": "taskManager markTaskAsRunning alerting:monitoring_alert_cluster_health", @@ -1152,11 +1152,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager markTaskAsRunning alerting:monitoring_alert_cluster_health", "transactionType": "taskManager", - "transactionsPerMinute": 1.86666666666667, + "transactionsPerMinute": 1.16666666666667, }, Object { - "averageResponseTime": 1798600, - "impact": 4.13189959005522, + "averageResponseTime": 1802239, + "impact": 4.16633706236838, "key": Object { "service.name": "kibana-frontend", "transaction.name": "GET /internal/spaces/_active_space", @@ -1164,11 +1164,11 @@ Array [ "serviceName": "kibana-frontend", "transactionName": "GET /internal/spaces/_active_space", "transactionType": "http-request", - "transactionsPerMinute": 0.166666666666667, + "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 167946.267857143, - "impact": 4.32122835139735, + "averageResponseTime": 169224.481481481, + "impact": 4.22503321777783, "key": Object { "service.name": "kibana", "transaction.name": "taskManager markTaskAsRunning alerting:monitoring_alert_jvm_memory_usage", @@ -1176,11 +1176,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager markTaskAsRunning alerting:monitoring_alert_jvm_memory_usage", "transactionType": "taskManager", - "transactionsPerMinute": 1.86666666666667, + "transactionsPerMinute": 1.33333333333333, }, Object { - "averageResponseTime": 171500.666666667, - "impact": 4.49151169382242, + "averageResponseTime": 171304.890909091, + "impact": 4.35620301138695, "key": Object { "service.name": "kibana", "transaction.name": "taskManager markTaskAsRunning alerting:monitoring_alert_nodes_changed", @@ -1188,11 +1188,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager markTaskAsRunning alerting:monitoring_alert_nodes_changed", "transactionType": "taskManager", - "transactionsPerMinute": 1.9, + "transactionsPerMinute": 1.16666666666667, }, Object { - "averageResponseTime": 173836.877192982, - "impact": 4.55270665967207, + "averageResponseTime": 173706.636363636, + "impact": 4.41728952052186, "key": Object { "service.name": "kibana", "transaction.name": "taskManager markTaskAsRunning alerting:monitoring_alert_missing_monitoring_data", @@ -1200,11 +1200,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager markTaskAsRunning alerting:monitoring_alert_missing_monitoring_data", "transactionType": "taskManager", - "transactionsPerMinute": 1.9, + "transactionsPerMinute": 1.36666666666667, }, Object { - "averageResponseTime": 173880.684210526, - "impact": 4.55385414570228, + "averageResponseTime": 173725.254545455, + "impact": 4.41776305935237, "key": Object { "service.name": "kibana", "transaction.name": "taskManager markTaskAsRunning alerting:monitoring_alert_kibana_version_mismatch", @@ -1212,23 +1212,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager markTaskAsRunning alerting:monitoring_alert_kibana_version_mismatch", "transactionType": "taskManager", - "transactionsPerMinute": 1.9, - }, - Object { - "averageResponseTime": 2800500, - "impact": 5.14703641053135, - "key": Object { - "service.name": "kibana-frontend", - "transaction.name": "/app/kibana_overview", - }, - "serviceName": "kibana-frontend", - "transactionName": "/app/kibana_overview", - "transactionType": "page-load", - "transactionsPerMinute": 0.133333333333333, + "transactionsPerMinute": 1.36666666666667, }, Object { - "averageResponseTime": 195498.172413793, - "impact": 5.20994548246537, + "averageResponseTime": 194504.142857143, + "impact": 5.03620430954926, "key": Object { "service.name": "kibana", "transaction.name": "taskManager markTaskAsRunning alerting:monitoring_alert_disk_usage", @@ -1236,11 +1224,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager markTaskAsRunning alerting:monitoring_alert_disk_usage", "transactionType": "taskManager", - "transactionsPerMinute": 1.93333333333333, + "transactionsPerMinute": 0.9, }, Object { - "averageResponseTime": 195530.5, - "impact": 5.21080713096623, + "averageResponseTime": 194559, + "impact": 5.03762492604077, "key": Object { "service.name": "kibana", "transaction.name": "taskManager markTaskAsRunning alerting:monitoring_alert_logstash_version_mismatch", @@ -1248,35 +1236,47 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager markTaskAsRunning alerting:monitoring_alert_logstash_version_mismatch", "transactionType": "taskManager", - "transactionsPerMinute": 1.93333333333333, + "transactionsPerMinute": 0.9, + }, + Object { + "averageResponseTime": 2806010, + "impact": 5.18964568872075, + "key": Object { + "service.name": "kibana-frontend", + "transaction.name": "/app/kibana_overview", + }, + "serviceName": "kibana-frontend", + "transactionName": "/app/kibana_overview", + "transactionType": "page-load", + "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 164445.447058824, - "impact": 6.42267277988279, + "averageResponseTime": 164575.780487805, + "impact": 6.23992799324149, "key": Object { "service.name": "kibana", - "transaction.name": "taskManager markTaskAsRunning alerting:monitoring_alert_thread_pool_search_rejections", + "transaction.name": "taskManager markTaskAsRunning alerting:monitoring_alert_thread_pool_write_rejections", }, "serviceName": "kibana", - "transactionName": "taskManager markTaskAsRunning alerting:monitoring_alert_thread_pool_search_rejections", + "transactionName": "taskManager markTaskAsRunning alerting:monitoring_alert_thread_pool_write_rejections", "transactionType": "taskManager", - "transactionsPerMinute": 2.83333333333333, + "transactionsPerMinute": 1.46666666666667, }, Object { - "averageResponseTime": 164462.105882353, - "impact": 6.42332349683064, + "averageResponseTime": 164588.268292683, + "impact": 6.24040153207199, "key": Object { "service.name": "kibana", - "transaction.name": "taskManager markTaskAsRunning alerting:monitoring_alert_thread_pool_write_rejections", + "transaction.name": "taskManager markTaskAsRunning alerting:monitoring_alert_thread_pool_search_rejections", }, "serviceName": "kibana", - "transactionName": "taskManager markTaskAsRunning alerting:monitoring_alert_thread_pool_write_rejections", + "transactionName": "taskManager markTaskAsRunning alerting:monitoring_alert_thread_pool_search_rejections", "transactionType": "taskManager", - "transactionsPerMinute": 2.83333333333333, + "transactionsPerMinute": 1.46666666666667, }, Object { - "averageResponseTime": 1496818.18181818, - "impact": 7.56562630920309, + "averageResponseTime": 1500252.09090909, + "impact": 7.6307443716881, "key": Object { "service.name": "kibana-frontend", "transaction.name": "POST /api/ui_counters/_report", @@ -1284,11 +1284,11 @@ Array [ "serviceName": "kibana-frontend", "transactionName": "POST /api/ui_counters/_report", "transactionType": "http-request", - "transactionsPerMinute": 0.366666666666667, + "transactionsPerMinute": 0.266666666666667, }, Object { - "averageResponseTime": 92216.7388888889, - "impact": 7.62721142949393, + "averageResponseTime": 92454.8222222222, + "impact": 7.69506750023189, "key": Object { "service.name": "kibana", "transaction.name": "GET /login", @@ -1296,11 +1296,11 @@ Array [ "serviceName": "kibana", "transactionName": "GET /login", "transactionType": "request", - "transactionsPerMinute": 6, + "transactionsPerMinute": 3.33333333333333, }, Object { - "averageResponseTime": 1045125, - "impact": 7.68372959705387, + "averageResponseTime": 1048831, + "impact": 7.75954462138365, "key": Object { "service.name": "kibana-frontend", "transaction.name": "GET /api/saved_objects_tagging/tags", @@ -1308,11 +1308,11 @@ Array [ "serviceName": "kibana-frontend", "transactionName": "GET /api/saved_objects_tagging/tags", "transactionType": "http-request", - "transactionsPerMinute": 0.533333333333333, + "transactionsPerMinute": 0.366666666666667, }, Object { - "averageResponseTime": 5716250, - "impact": 10.5067198587944, + "averageResponseTime": 5727231, + "impact": 10.5932065323979, "key": Object { "service.name": "opbeans-rum", "transaction.name": "/orders", @@ -1323,8 +1323,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 6880750, - "impact": 12.6472845078564, + "averageResponseTime": 6905855, + "impact": 12.7733793080345, "key": Object { "service.name": "kibana-frontend", "transaction.name": "/services", @@ -1335,8 +1335,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 2547818.18181818, - "impact": 12.8784360790196, + "averageResponseTime": 2556275.36363636, + "impact": 13.0025688649162, "key": Object { "service.name": "kibana-frontend", "transaction.name": "POST /../api/console/proxy", @@ -1344,11 +1344,11 @@ Array [ "serviceName": "kibana-frontend", "transactionName": "POST /../api/console/proxy", "transactionType": "http-request", - "transactionsPerMinute": 0.366666666666667, + "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 893343.790697674, - "impact": 17.6520988252468, + "averageResponseTime": 895713.232558139, + "impact": 17.8103938129266, "key": Object { "service.name": "opbeans-node", "transaction.name": "Process completed order", @@ -1356,11 +1356,11 @@ Array [ "serviceName": "opbeans-node", "transactionName": "Process completed order", "transactionType": "Worker", - "transactionsPerMinute": 1.43333333333333, + "transactionsPerMinute": 1.06666666666667, }, Object { - "averageResponseTime": 1008091.65853659, - "impact": 18.9930421768669, + "averageResponseTime": 1010587.09756098, + "impact": 19.1599804047412, "key": Object { "service.name": "opbeans-node", "transaction.name": "Update shipping status", @@ -1368,11 +1368,11 @@ Array [ "serviceName": "opbeans-node", "transactionName": "Update shipping status", "transactionType": "Worker", - "transactionsPerMinute": 1.36666666666667, + "transactionsPerMinute": 1.16666666666667, }, Object { - "averageResponseTime": 119589.313888889, - "impact": 19.7836425889371, + "averageResponseTime": 120075.8, + "impact": 19.9892361479233, "key": Object { "service.name": "opbeans-python", "transaction.name": "opbeans.tasks.update_stats", @@ -1380,11 +1380,11 @@ Array [ "serviceName": "opbeans-python", "transactionName": "opbeans.tasks.update_stats", "transactionType": "celery", - "transactionsPerMinute": 12, + "transactionsPerMinute": 3.2, }, Object { - "averageResponseTime": 990251.295454545, - "impact": 20.022102777571, + "averageResponseTime": 986611.622222222, + "impact": 20.5303999304564, "key": Object { "service.name": "opbeans-node", "transaction.name": "Process payment", @@ -1392,11 +1392,11 @@ Array [ "serviceName": "opbeans-node", "transactionName": "Process payment", "transactionType": "Worker", - "transactionsPerMinute": 1.46666666666667, + "transactionsPerMinute": 1.2, }, Object { - "averageResponseTime": 275786.56684492, - "impact": 23.6989435063492, + "averageResponseTime": 276820.333333333, + "impact": 23.8095911276137, "key": Object { "service.name": "kibana", "transaction.name": "GET /", @@ -1404,11 +1404,11 @@ Array [ "serviceName": "kibana", "transactionName": "GET /", "transactionType": "request", - "transactionsPerMinute": 6.23333333333333, + "transactionsPerMinute": 3.23333333333333, }, Object { - "averageResponseTime": 292147.652406417, - "impact": 25.104934656369, + "averageResponseTime": 293182.311827957, + "impact": 25.2169485318692, "key": Object { "service.name": "kibana", "transaction.name": "GET /spaces/space_selector", @@ -1416,11 +1416,11 @@ Array [ "serviceName": "kibana", "transactionName": "GET /spaces/space_selector", "transactionType": "request", - "transactionsPerMinute": 6.23333333333333, + "transactionsPerMinute": 3.53333333333333, }, Object { - "averageResponseTime": 57975578, - "impact": 26.6416408710168, + "averageResponseTime": 58195967, + "impact": 26.9113560188584, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run apm-telemetry-task", @@ -1431,8 +1431,8 @@ Array [ "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 1750161.27027027, - "impact": 29.7575406134574, + "averageResponseTime": 1750583.88888889, + "impact": 29.1426548027802, "key": Object { "service.name": "opbeans-python", "transaction.name": "opbeans.tasks.sync_customers", @@ -1440,11 +1440,11 @@ Array [ "serviceName": "opbeans-python", "transactionName": "opbeans.tasks.sync_customers", "transactionType": "celery", - "transactionsPerMinute": 1.23333333333333, + "transactionsPerMinute": 1.1, }, Object { - "averageResponseTime": 116474.489148581, - "impact": 32.0609003050397, + "averageResponseTime": 116325.056951424, + "impact": 32.1138515351995, "key": Object { "service.name": "kibana", "transaction.name": "taskManager markAvailableTasksAsClaimed", @@ -1452,11 +1452,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager markAvailableTasksAsClaimed", "transactionType": "taskManager", - "transactionsPerMinute": 19.9666666666667, + "transactionsPerMinute": 2, }, Object { - "averageResponseTime": 1366238.94642857, - "impact": 35.1587734417506, + "averageResponseTime": 1369390.40740741, + "impact": 34.1953058003244, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run alerting:monitoring_alert_cpu_usage", @@ -1464,11 +1464,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager run alerting:monitoring_alert_cpu_usage", "transactionType": "taskManager", - "transactionsPerMinute": 1.86666666666667, + "transactionsPerMinute": 1.23333333333333, }, Object { - "averageResponseTime": 1377926.98214286, - "impact": 35.4595599981591, + "averageResponseTime": 1381261.22222222, + "impact": 34.4917411082194, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run alerting:monitoring_alert_elasticsearch_version_mismatch", @@ -1476,11 +1476,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager run alerting:monitoring_alert_elasticsearch_version_mismatch", "transactionType": "taskManager", - "transactionsPerMinute": 1.86666666666667, + "transactionsPerMinute": 1.23333333333333, }, Object { - "averageResponseTime": 1410581.25, - "impact": 36.2999034930702, + "averageResponseTime": 1415622.11111111, + "impact": 35.3497934690912, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run alerting:monitoring_alert_cluster_health", @@ -1488,11 +1488,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager run alerting:monitoring_alert_cluster_health", "transactionType": "taskManager", - "transactionsPerMinute": 1.86666666666667, + "transactionsPerMinute": 1.13333333333333, }, Object { - "averageResponseTime": 1461959.30357143, - "impact": 37.6220955351282, + "averageResponseTime": 1469097.66666667, + "impact": 36.6851729711102, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run alerting:monitoring_alert_license_expiration", @@ -1500,11 +1500,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager run alerting:monitoring_alert_license_expiration", "transactionType": "taskManager", - "transactionsPerMinute": 1.86666666666667, + "transactionsPerMinute": 1.16666666666667, }, Object { - "averageResponseTime": 1543576.98214286, - "impact": 39.7224912799448, + "averageResponseTime": 1553520.77777778, + "impact": 38.7933678445103, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run alerting:monitoring_alert_jvm_memory_usage", @@ -1512,11 +1512,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager run alerting:monitoring_alert_jvm_memory_usage", "transactionType": "taskManager", - "transactionsPerMinute": 1.86666666666667, + "transactionsPerMinute": 1.23333333333333, }, Object { - "averageResponseTime": 1607992.80701754, - "impact": 42.1191511902916, + "averageResponseTime": 1604038.11111111, + "impact": 40.0548752889708, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run alerting:monitoring_alert_nodes_changed", @@ -1524,11 +1524,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager run alerting:monitoring_alert_nodes_changed", "transactionType": "taskManager", - "transactionsPerMinute": 1.9, + "transactionsPerMinute": 1.03333333333333, }, Object { - "averageResponseTime": 1647217.96491228, - "impact": 43.1466194645661, + "averageResponseTime": 1644922.25925926, + "impact": 41.0758250075357, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run alerting:monitoring_alert_kibana_version_mismatch", @@ -1536,11 +1536,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager run alerting:monitoring_alert_kibana_version_mismatch", "transactionType": "taskManager", - "transactionsPerMinute": 1.9, + "transactionsPerMinute": 1.26666666666667, }, Object { - "averageResponseTime": 1659837.4137931, - "impact": 44.2399461761499, + "averageResponseTime": 1677749.85714286, + "impact": 43.4473065458151, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run alerting:monitoring_alert_logstash_version_mismatch", @@ -1548,23 +1548,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager run alerting:monitoring_alert_logstash_version_mismatch", "transactionType": "taskManager", - "transactionsPerMinute": 1.93333333333333, - }, - Object { - "averageResponseTime": 5172947.36842105, - "impact": 45.1661287031269, - "key": Object { - "service.name": "kibana-frontend", - "transaction.name": "Click - div", - }, - "serviceName": "kibana-frontend", - "transactionName": "Click - div", - "transactionType": "user-interaction", - "transactionsPerMinute": 0.633333333333333, + "transactionsPerMinute": 0.9, }, Object { - "averageResponseTime": 1735464.70689655, - "impact": 46.2556903554213, + "averageResponseTime": 1740724.52727273, + "impact": 44.2731587286529, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run alerting:monitoring_alert_disk_usage", @@ -1572,11 +1560,23 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager run alerting:monitoring_alert_disk_usage", "transactionType": "taskManager", - "transactionsPerMinute": 1.93333333333333, + "transactionsPerMinute": 0.9, + }, + Object { + "averageResponseTime": 5186451.21052632, + "impact": 45.5692511555897, + "key": Object { + "service.name": "kibana-frontend", + "transaction.name": "Click - div", + }, + "serviceName": "kibana-frontend", + "transactionName": "Click - div", + "transactionType": "user-interaction", + "transactionsPerMinute": 0.333333333333333, }, Object { - "averageResponseTime": 1801431.05263158, - "impact": 47.1860947302795, + "averageResponseTime": 1823761.61818182, + "impact": 46.3851419126971, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run alerting:monitoring_alert_missing_monitoring_data", @@ -1584,11 +1584,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager run alerting:monitoring_alert_missing_monitoring_data", "transactionType": "taskManager", - "transactionsPerMinute": 1.9, + "transactionsPerMinute": 1.3, }, Object { - "averageResponseTime": 1362436.2, - "impact": 53.217867226032, + "averageResponseTime": 1371909.24390244, + "impact": 52.0221356651199, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run alerting:monitoring_alert_thread_pool_search_rejections", @@ -1596,11 +1596,11 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager run alerting:monitoring_alert_thread_pool_search_rejections", "transactionType": "taskManager", - "transactionsPerMinute": 2.83333333333333, + "transactionsPerMinute": 1.43333333333333, }, Object { - "averageResponseTime": 1388938.89411765, - "impact": 54.2530995277316, + "averageResponseTime": 1399682.12195122, + "impact": 53.075286024159, "key": Object { "service.name": "kibana", "transaction.name": "taskManager run alerting:monitoring_alert_thread_pool_write_rejections", @@ -1608,10 +1608,10 @@ Array [ "serviceName": "kibana", "transactionName": "taskManager run alerting:monitoring_alert_thread_pool_write_rejections", "transactionType": "taskManager", - "transactionsPerMinute": 2.83333333333333, + "transactionsPerMinute": 1.43333333333333, }, Object { - "averageResponseTime": 550905.994936709, + "averageResponseTime": 553058.519181586, "impact": 100, "key": Object { "service.name": "kibana", @@ -1620,7 +1620,7 @@ Array [ "serviceName": "kibana", "transactionName": "POST /api/apm/settings/agent-configuration/search", "transactionType": "request", - "transactionsPerMinute": 13.1666666666667, + "transactionsPerMinute": 5.4, }, ] `; diff --git a/x-pack/test/apm_api_integration/tests/traces/top_traces.ts b/x-pack/test/apm_api_integration/tests/traces/top_traces.ts index 40f87be3dc402..28b12d4865c1e 100644 --- a/x-pack/test/apm_api_integration/tests/traces/top_traces.ts +++ b/x-pack/test/apm_api_integration/tests/traces/top_traces.ts @@ -60,7 +60,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { expectSnapshot(firstItem).toMatchInline(` Object { - "averageResponseTime": 1733, + "averageResponseTime": 1735, "impact": 0, "key": Object { "service.name": "opbeans-java", @@ -75,7 +75,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { expectSnapshot(lastItem).toMatchInline(` Object { - "averageResponseTime": 550905.994936709, + "averageResponseTime": 553058.519181586, "impact": 100, "key": Object { "service.name": "kibana", @@ -84,7 +84,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { "serviceName": "kibana", "transactionName": "POST /api/apm/settings/agent-configuration/search", "transactionType": "request", - "transactionsPerMinute": 13.1666666666667, + "transactionsPerMinute": 5.4, } `); diff --git a/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/error_rate.snap b/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/error_rate.snap index 7ec68bbc0a9fd..3db729f5905e3 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/error_rate.snap +++ b/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/error_rate.snap @@ -3,986 +3,266 @@ exports[`APM API tests basic apm_8.0.0 Error rate when data is loaded returns the transaction error rate has the correct error rate 1`] = ` Array [ Object { - "x": 1607435850000, + "x": 1607435820000, "y": null, }, Object { "x": 1607435880000, "y": 0, }, - Object { - "x": 1607435910000, - "y": null, - }, Object { "x": 1607435940000, "y": 0, }, - Object { - "x": 1607435970000, - "y": null, - }, Object { "x": 1607436000000, "y": 0, }, - Object { - "x": 1607436030000, - "y": 0, - }, Object { "x": 1607436060000, "y": null, }, - Object { - "x": 1607436090000, - "y": null, - }, Object { "x": 1607436120000, "y": 0, }, - Object { - "x": 1607436150000, - "y": null, - }, Object { "x": 1607436180000, "y": null, }, - Object { - "x": 1607436210000, - "y": null, - }, Object { "x": 1607436240000, "y": 0, }, - Object { - "x": 1607436270000, - "y": null, - }, Object { "x": 1607436300000, - "y": null, - }, - Object { - "x": 1607436330000, "y": 1, }, Object { "x": 1607436360000, "y": 0, }, - Object { - "x": 1607436390000, - "y": 0, - }, Object { "x": 1607436420000, "y": null, }, - Object { - "x": 1607436450000, - "y": null, - }, Object { "x": 1607436480000, - "y": 0, - }, - Object { - "x": 1607436510000, - "y": 0.2, + "y": 0.142857142857143, }, Object { "x": 1607436540000, "y": null, }, - Object { - "x": 1607436570000, - "y": null, - }, Object { "x": 1607436600000, - "y": 0.5, - }, - Object { - "x": 1607436630000, - "y": 0.142857142857143, + "y": 0.222222222222222, }, Object { "x": 1607436660000, "y": null, }, - Object { - "x": 1607436690000, - "y": null, - }, Object { "x": 1607436720000, - "y": null, - }, - Object { - "x": 1607436750000, - "y": 0.5, + "y": 1, }, Object { "x": 1607436780000, - "y": null, - }, - Object { - "x": 1607436810000, "y": 0, }, Object { "x": 1607436840000, - "y": 1, - }, - Object { - "x": 1607436870000, - "y": 0, + "y": 0.333333333333333, }, Object { "x": 1607436900000, "y": null, }, - Object { - "x": 1607436930000, - "y": null, - }, Object { "x": 1607436960000, "y": 0, }, - Object { - "x": 1607436990000, - "y": 0, - }, Object { "x": 1607437020000, "y": null, }, - Object { - "x": 1607437050000, - "y": null, - }, Object { "x": 1607437080000, "y": 0, }, - Object { - "x": 1607437110000, - "y": 0, - }, Object { "x": 1607437140000, "y": null, }, - Object { - "x": 1607437170000, - "y": null, - }, Object { "x": 1607437200000, - "y": 0, - }, - Object { - "x": 1607437230000, - "y": 0.428571428571429, + "y": 0.285714285714286, }, Object { "x": 1607437260000, "y": 0, }, - Object { - "x": 1607437290000, - "y": null, - }, Object { "x": 1607437320000, - "y": 0, - }, - Object { - "x": 1607437350000, - "y": 0.5, + "y": 0.333333333333333, }, Object { "x": 1607437380000, "y": null, }, - Object { - "x": 1607437410000, - "y": null, - }, Object { "x": 1607437440000, - "y": 1, - }, - Object { - "x": 1607437470000, - "y": 0.333333333333333, + "y": 0.5, }, Object { "x": 1607437500000, "y": null, }, - Object { - "x": 1607437530000, - "y": null, - }, Object { "x": 1607437560000, "y": 0, }, - Object { - "x": 1607437590000, - "y": null, - }, Object { "x": 1607437620000, "y": null, }, - Object { - "x": 1607437650000, - "y": null, - }, ] `; exports[`APM API tests basic apm_8.0.0 Error rate when data is loaded returns the transaction error rate with comparison data has the correct error rate 1`] = ` Array [ Object { - "x": 1607436770000, + "x": 1607436720000, "y": null, }, Object { "x": 1607436780000, - "y": null, - }, - Object { - "x": 1607436790000, - "y": null, - }, - Object { - "x": 1607436800000, - "y": null, - }, - Object { - "x": 1607436810000, - "y": null, - }, - Object { - "x": 1607436820000, "y": 0, }, - Object { - "x": 1607436830000, - "y": null, - }, Object { "x": 1607436840000, - "y": null, - }, - Object { - "x": 1607436850000, - "y": null, - }, - Object { - "x": 1607436860000, - "y": 1, - }, - Object { - "x": 1607436870000, - "y": 0, - }, - Object { - "x": 1607436880000, - "y": 0, - }, - Object { - "x": 1607436890000, - "y": null, + "y": 0.333333333333333, }, Object { "x": 1607436900000, "y": null, }, - Object { - "x": 1607436910000, - "y": null, - }, - Object { - "x": 1607436920000, - "y": null, - }, - Object { - "x": 1607436930000, - "y": null, - }, - Object { - "x": 1607436940000, - "y": null, - }, - Object { - "x": 1607436950000, - "y": null, - }, Object { "x": 1607436960000, - "y": null, - }, - Object { - "x": 1607436970000, - "y": null, - }, - Object { - "x": 1607436980000, - "y": 0, - }, - Object { - "x": 1607436990000, - "y": 0, - }, - Object { - "x": 1607437000000, "y": 0, }, - Object { - "x": 1607437010000, - "y": null, - }, Object { "x": 1607437020000, "y": null, }, - Object { - "x": 1607437030000, - "y": null, - }, - Object { - "x": 1607437040000, - "y": null, - }, - Object { - "x": 1607437050000, - "y": null, - }, - Object { - "x": 1607437060000, - "y": null, - }, - Object { - "x": 1607437070000, - "y": null, - }, Object { "x": 1607437080000, - "y": null, - }, - Object { - "x": 1607437090000, - "y": null, - }, - Object { - "x": 1607437100000, "y": 0, }, - Object { - "x": 1607437110000, - "y": 0, - }, - Object { - "x": 1607437120000, - "y": null, - }, - Object { - "x": 1607437130000, - "y": null, - }, Object { "x": 1607437140000, "y": null, }, Object { - "x": 1607437150000, - "y": null, - }, - Object { - "x": 1607437160000, - "y": null, + "x": 1607437200000, + "y": 0.285714285714286, }, Object { - "x": 1607437170000, - "y": null, + "x": 1607437260000, + "y": 0, }, Object { - "x": 1607437180000, - "y": null, + "x": 1607437320000, + "y": 0.333333333333333, }, Object { - "x": 1607437190000, + "x": 1607437380000, "y": null, }, Object { - "x": 1607437200000, - "y": null, + "x": 1607437440000, + "y": 0.5, }, Object { - "x": 1607437210000, + "x": 1607437500000, "y": null, }, Object { - "x": 1607437220000, - "y": 0, - }, - Object { - "x": 1607437230000, - "y": 0.6, - }, - Object { - "x": 1607437240000, + "x": 1607437560000, "y": 0, }, Object { - "x": 1607437250000, + "x": 1607437620000, "y": null, }, +] +`; + +exports[`APM API tests basic apm_8.0.0 Error rate when data is loaded returns the transaction error rate with comparison data has the correct error rate 2`] = ` +Array [ Object { - "x": 1607437260000, + "x": 1607436720000, "y": null, }, Object { - "x": 1607437270000, + "x": 1607436780000, "y": 0, }, Object { - "x": 1607437280000, - "y": null, - }, - Object { - "x": 1607437290000, - "y": null, + "x": 1607436840000, + "y": 0, }, Object { - "x": 1607437300000, - "y": null, + "x": 1607436900000, + "y": 0, }, Object { - "x": 1607437310000, + "x": 1607436960000, "y": null, }, Object { - "x": 1607437320000, - "y": null, + "x": 1607437020000, + "y": 0, }, Object { - "x": 1607437330000, + "x": 1607437080000, "y": null, }, Object { - "x": 1607437340000, + "x": 1607437140000, "y": 0, }, Object { - "x": 1607437350000, - "y": null, + "x": 1607437200000, + "y": 1, }, Object { - "x": 1607437360000, - "y": 0.5, + "x": 1607437260000, + "y": 0, }, Object { - "x": 1607437370000, + "x": 1607437320000, "y": null, }, Object { "x": 1607437380000, - "y": null, + "y": 0.142857142857143, }, Object { - "x": 1607437390000, + "x": 1607437440000, "y": null, }, Object { - "x": 1607437400000, - "y": null, + "x": 1607437500000, + "y": 0.222222222222222, }, Object { - "x": 1607437410000, - "y": null, - }, - Object { - "x": 1607437420000, - "y": null, - }, - Object { - "x": 1607437430000, - "y": null, - }, - Object { - "x": 1607437440000, - "y": null, - }, - Object { - "x": 1607437450000, - "y": null, - }, - Object { - "x": 1607437460000, - "y": 1, - }, - Object { - "x": 1607437470000, - "y": 0, - }, - Object { - "x": 1607437480000, - "y": 1, - }, - Object { - "x": 1607437490000, - "y": null, - }, - Object { - "x": 1607437500000, - "y": null, - }, - Object { - "x": 1607437510000, - "y": null, - }, - Object { - "x": 1607437520000, - "y": null, - }, - Object { - "x": 1607437530000, - "y": null, - }, - Object { - "x": 1607437540000, - "y": null, - }, - Object { - "x": 1607437550000, - "y": null, - }, - Object { - "x": 1607437560000, - "y": null, - }, - Object { - "x": 1607437570000, - "y": 0, - }, - Object { - "x": 1607437580000, - "y": null, - }, - Object { - "x": 1607437590000, - "y": null, - }, - Object { - "x": 1607437600000, - "y": null, - }, - Object { - "x": 1607437610000, + "x": 1607437560000, "y": null, }, Object { "x": 1607437620000, - "y": null, - }, - Object { - "x": 1607437630000, - "y": null, - }, - Object { - "x": 1607437640000, - "y": null, - }, - Object { - "x": 1607437650000, - "y": null, - }, - Object { - "x": 1607437660000, - "y": null, - }, - Object { - "x": 1607437670000, - "y": null, - }, -] -`; - -exports[`APM API tests basic apm_8.0.0 Error rate when data is loaded returns the transaction error rate with comparison data has the correct error rate 2`] = ` -Array [ - Object { - "x": 1607436770000, - "y": null, - }, - Object { - "x": 1607436780000, - "y": null, - }, - Object { - "x": 1607436790000, - "y": null, - }, - Object { - "x": 1607436800000, - "y": 0, - }, - Object { - "x": 1607436810000, - "y": null, - }, - Object { - "x": 1607436820000, - "y": null, - }, - Object { - "x": 1607436830000, - "y": null, - }, - Object { - "x": 1607436840000, - "y": 0, - }, - Object { - "x": 1607436850000, - "y": null, - }, - Object { - "x": 1607436860000, - "y": null, - }, - Object { - "x": 1607436870000, - "y": null, - }, - Object { - "x": 1607436880000, - "y": null, - }, - Object { - "x": 1607436890000, - "y": null, - }, - Object { - "x": 1607436900000, - "y": null, - }, - Object { - "x": 1607436910000, - "y": 0, - }, - Object { - "x": 1607436920000, - "y": 0, - }, - Object { - "x": 1607436930000, - "y": 0, - }, - Object { - "x": 1607436940000, - "y": null, - }, - Object { - "x": 1607436950000, - "y": null, - }, - Object { - "x": 1607436960000, - "y": null, - }, - Object { - "x": 1607436970000, - "y": null, - }, - Object { - "x": 1607436980000, - "y": null, - }, - Object { - "x": 1607436990000, - "y": null, - }, - Object { - "x": 1607437000000, - "y": null, - }, - Object { - "x": 1607437010000, - "y": null, - }, - Object { - "x": 1607437020000, - "y": null, - }, - Object { - "x": 1607437030000, - "y": 0, - }, - Object { - "x": 1607437040000, - "y": 0, - }, - Object { - "x": 1607437050000, - "y": null, - }, - Object { - "x": 1607437060000, - "y": null, - }, - Object { - "x": 1607437070000, - "y": null, - }, - Object { - "x": 1607437080000, - "y": null, - }, - Object { - "x": 1607437090000, - "y": null, - }, - Object { - "x": 1607437100000, - "y": null, - }, - Object { - "x": 1607437110000, - "y": null, - }, - Object { - "x": 1607437120000, - "y": null, - }, - Object { - "x": 1607437130000, - "y": null, - }, - Object { - "x": 1607437140000, - "y": null, - }, - Object { - "x": 1607437150000, - "y": null, - }, - Object { - "x": 1607437160000, - "y": 0, - }, - Object { - "x": 1607437170000, - "y": null, - }, - Object { - "x": 1607437180000, - "y": null, - }, - Object { - "x": 1607437190000, - "y": null, - }, - Object { - "x": 1607437200000, - "y": null, - }, - Object { - "x": 1607437210000, - "y": null, - }, - Object { - "x": 1607437220000, - "y": null, - }, - Object { - "x": 1607437230000, - "y": null, - }, - Object { - "x": 1607437240000, "y": 1, }, - Object { - "x": 1607437250000, - "y": null, - }, - Object { - "x": 1607437260000, - "y": null, - }, - Object { - "x": 1607437270000, - "y": null, - }, - Object { - "x": 1607437280000, - "y": 0, - }, - Object { - "x": 1607437290000, - "y": 0, - }, - Object { - "x": 1607437300000, - "y": null, - }, - Object { - "x": 1607437310000, - "y": null, - }, - Object { - "x": 1607437320000, - "y": null, - }, - Object { - "x": 1607437330000, - "y": null, - }, - Object { - "x": 1607437340000, - "y": null, - }, - Object { - "x": 1607437350000, - "y": null, - }, - Object { - "x": 1607437360000, - "y": null, - }, - Object { - "x": 1607437370000, - "y": null, - }, - Object { - "x": 1607437380000, - "y": null, - }, - Object { - "x": 1607437390000, - "y": null, - }, - Object { - "x": 1607437400000, - "y": 0, - }, - Object { - "x": 1607437410000, - "y": 0, - }, - Object { - "x": 1607437420000, - "y": 0.25, - }, - Object { - "x": 1607437430000, - "y": null, - }, - Object { - "x": 1607437440000, - "y": null, - }, - Object { - "x": 1607437450000, - "y": null, - }, - Object { - "x": 1607437460000, - "y": null, - }, - Object { - "x": 1607437470000, - "y": null, - }, - Object { - "x": 1607437480000, - "y": null, - }, - Object { - "x": 1607437490000, - "y": null, - }, - Object { - "x": 1607437500000, - "y": null, - }, - Object { - "x": 1607437510000, - "y": null, - }, - Object { - "x": 1607437520000, - "y": 0.5, - }, - Object { - "x": 1607437530000, - "y": 0.2, - }, - Object { - "x": 1607437540000, - "y": 0, - }, - Object { - "x": 1607437550000, - "y": null, - }, - Object { - "x": 1607437560000, - "y": null, - }, - Object { - "x": 1607437570000, - "y": null, - }, - Object { - "x": 1607437580000, - "y": null, - }, - Object { - "x": 1607437590000, - "y": null, - }, - Object { - "x": 1607437600000, - "y": null, - }, - Object { - "x": 1607437610000, - "y": null, - }, - Object { - "x": 1607437620000, - "y": null, - }, - Object { - "x": 1607437630000, - "y": null, - }, - Object { - "x": 1607437640000, - "y": null, - }, - Object { - "x": 1607437650000, - "y": 1, - }, - Object { - "x": 1607437660000, - "y": 0, - }, - Object { - "x": 1607437670000, - "y": null, - }, ] `; diff --git a/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/latency.snap b/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/latency.snap index 468776bf692f4..0a4a788b421c9 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/latency.snap +++ b/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/latency.snap @@ -4,75 +4,43 @@ exports[`APM API tests basic apm_8.0.0 Latency with a basic license when data is Array [ Object { "x": 1607436780000, - "y": 51029, + "y": 36479, }, Object { - "x": 1607436820000, - "y": 38124, - }, - Object { - "x": 1607436860000, - "y": 16327, - }, - Object { - "x": 1607436980000, - "y": 35617.5, - }, - Object { - "x": 1607436990000, - "y": 34599.75, - }, - Object { - "x": 1607437100000, - "y": 26980, - }, - Object { - "x": 1607437110000, - "y": 42808, - }, - Object { - "x": 1607437130000, - "y": 22230.5, + "x": 1607436840000, + "y": 16383, }, Object { - "x": 1607437220000, - "y": 34973, + "x": 1607436960000, + "y": 35081.6666666667, }, Object { - "x": 1607437230000, - "y": 19284.2, + "x": 1607437080000, + "y": 31019, }, Object { - "x": 1607437240000, - "y": 9280, + "x": 1607437140000, + "y": 22271, }, Object { - "x": 1607437250000, - "y": 42777, + "x": 1607437200000, + "y": 21972.3333333333, }, Object { "x": 1607437260000, - "y": 10702, - }, - Object { - "x": 1607437340000, - "y": 22452, - }, - Object { - "x": 1607437470000, - "y": 14495.5, + "y": 21033.6666666667, }, Object { - "x": 1607437480000, - "y": 11644.5714285714, + "x": 1607437320000, + "y": 22559, }, Object { - "x": 1607437570000, - "y": 17359.6666666667, + "x": 1607437440000, + "y": 12704.4545454545, }, Object { - "x": 1607437590000, - "y": 11394.2, + "x": 1607437560000, + "y": 13687, }, ] `; @@ -80,88 +48,44 @@ Array [ exports[`APM API tests basic apm_8.0.0 Latency with a basic license when data is loaded time comparison returns some data 2`] = ` Array [ Object { - "x": 1607436800000, - "y": 23448.25, - }, - Object { - "x": 1607436820000, - "y": 25181, + "x": 1607436780000, + "y": 24047, }, Object { "x": 1607436840000, - "y": 16834, - }, - Object { - "x": 1607436910000, - "y": 21582, - }, - Object { - "x": 1607437040000, - "y": 31800, - }, - Object { - "x": 1607437050000, - "y": 21341, - }, - Object { - "x": 1607437060000, - "y": 21108.5, - }, - Object { - "x": 1607437150000, - "y": 12147.3333333333, - }, - Object { - "x": 1607437160000, - "y": 23941.5, + "y": 16895, }, Object { - "x": 1607437180000, - "y": 18244, - }, - Object { - "x": 1607437240000, - "y": 24359.5, - }, - Object { - "x": 1607437280000, - "y": 27767, - }, - Object { - "x": 1607437290000, - "y": 21909.6666666667, - }, - Object { - "x": 1607437390000, - "y": 31521, + "x": 1607436900000, + "y": 21631, }, Object { - "x": 1607437410000, - "y": 20227.5, + "x": 1607437020000, + "y": 22980.3333333333, }, Object { - "x": 1607437420000, - "y": 18664, + "x": 1607437140000, + "y": 17145.6666666667, }, Object { - "x": 1607437510000, - "y": 14197.5, + "x": 1607437200000, + "y": 24383, }, Object { - "x": 1607437520000, - "y": 19199.8571428571, + "x": 1607437260000, + "y": 24271, }, Object { - "x": 1607437540000, - "y": 63745.75, + "x": 1607437380000, + "y": 22711, }, Object { - "x": 1607437640000, - "y": 63220, + "x": 1607437500000, + "y": 32234.0769230769, }, Object { - "x": 1607437660000, - "y": 20040, + "x": 1607437620000, + "y": 63407, }, ] `; diff --git a/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/top_transaction_groups.snap b/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/top_transaction_groups.snap index 67a02e416de51..d1a1bf56c504c 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/top_transaction_groups.snap +++ b/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/top_transaction_groups.snap @@ -3,7 +3,7 @@ exports[`APM API tests basic apm_8.0.0 Top transaction groups when data is loaded returns the correct buckets (when ignoring samples) 1`] = ` Array [ Object { - "averageResponseTime": 2722.75, + "averageResponseTime": 2731, "impact": 0, "key": "GET /*", "p95": 3504, @@ -13,8 +13,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 11083.5, - "impact": 0.791851708281718, + "averageResponseTime": 11151, + "impact": 0.796826141612071, "key": "GET /api/products/:id", "p95": 17632, "serviceName": "opbeans-node", @@ -23,28 +23,28 @@ Array [ "transactionsPerMinute": 0.0666666666666667, }, Object { - "averageResponseTime": 12828, - "impact": 1.03686506498577, + "averageResponseTime": 12887, + "impact": 1.03997786983119, "key": "GET /api/orders/:id", "p95": 22128, "serviceName": "opbeans-node", "transactionName": "GET /api/orders/:id", "transactionType": "request", - "transactionsPerMinute": 0.0666666666666667, + "transactionsPerMinute": 0.0333333333333333, }, Object { - "averageResponseTime": 11634, - "impact": 2.50315308103067, + "averageResponseTime": 11655, + "impact": 2.4998686896629, "key": "GET /api/products", "p95": 21728, "serviceName": "opbeans-node", "transactionName": "GET /api/products", "transactionType": "request", - "transactionsPerMinute": 0.133333333333333, + "transactionsPerMinute": 0.1, }, Object { - "averageResponseTime": 15788.6666666667, - "impact": 2.56143943415889, + "averageResponseTime": 15817.6666666667, + "impact": 2.55820549542515, "key": "GET /api/types", "p95": 21600, "serviceName": "opbeans-node", @@ -53,8 +53,8 @@ Array [ "transactionsPerMinute": 0.1, }, Object { - "averageResponseTime": 12519.25, - "impact": 2.75181811287047, + "averageResponseTime": 12559, + "impact": 2.75310505177129, "key": "GET /api/products/:id/customers", "p95": 28384, "serviceName": "opbeans-node", @@ -63,8 +63,8 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 17371.25, - "impact": 4.11473563276508, + "averageResponseTime": 17391, + "impact": 4.10668702268692, "key": "GET /api/orders", "p95": 21600, "serviceName": "opbeans-node", @@ -73,18 +73,18 @@ Array [ "transactionsPerMinute": 0.133333333333333, }, Object { - "averageResponseTime": 12698.8571428571, - "impact": 5.47758292813784, + "averageResponseTime": 12739.5714285714, + "impact": 5.48022816484175, "key": "GET /api/products/top", "p95": 23024, "serviceName": "opbeans-node", "transactionName": "GET /api/products/top", "transactionType": "request", - "transactionsPerMinute": 0.233333333333333, + "transactionsPerMinute": 0.2, }, Object { - "averageResponseTime": 20919.4, - "impact": 6.58045904365437, + "averageResponseTime": 20984.6, + "impact": 6.58295486776174, "key": "GET /api/customers/:id", "p95": 58592, "serviceName": "opbeans-node", @@ -93,8 +93,8 @@ Array [ "transactionsPerMinute": 0.166666666666667, }, Object { - "averageResponseTime": 17268.1428571429, - "impact": 7.72371425922961, + "averageResponseTime": 17301.8571428571, + "impact": 7.71677585850698, "key": "GET /api/types/:id", "p95": 35040, "serviceName": "opbeans-node", @@ -103,34 +103,34 @@ Array [ "transactionsPerMinute": 0.233333333333333, }, Object { - "averageResponseTime": 22856.6666666667, - "impact": 8.86577565793355, + "averageResponseTime": 22900.3333333333, + "impact": 8.85753003505111, "key": "GET /api/stats", "p95": 44768, "serviceName": "opbeans-node", "transactionName": "GET /api/stats", "transactionType": "request", - "transactionsPerMinute": 0.2, + "transactionsPerMinute": 0.166666666666667, }, Object { - "averageResponseTime": 34805.1666666667, - "impact": 13.9002418532532, + "averageResponseTime": 34943, + "impact": 13.9177752177125, "key": "GET /api/customers", "p95": 42880, "serviceName": "opbeans-node", "transactionName": "GET /api/customers", "transactionType": "request", - "transactionsPerMinute": 0.2, + "transactionsPerMinute": 0.166666666666667, }, Object { - "averageResponseTime": 34997.4390243902, + "averageResponseTime": 35093.6341463415, "impact": 100, "key": "GET /api", "p95": 103392, "serviceName": "opbeans-node", "transactionName": "GET /api", "transactionType": "request", - "transactionsPerMinute": 1.36666666666667, + "transactionsPerMinute": 0.9, }, ] `; diff --git a/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/transactions_groups_detailed_statistics.snap b/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/transactions_groups_detailed_statistics.snap index 64336a4c65451..c3160aa50f71d 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/transactions_groups_detailed_statistics.snap +++ b/x-pack/test/apm_api_integration/tests/transactions/__snapshots__/transactions_groups_detailed_statistics.snap @@ -158,7 +158,7 @@ Array [ }, Object { "x": 1607436960000, - "y": 30501, + "y": 30527, }, Object { "x": 1607437020000, @@ -174,7 +174,7 @@ Array [ }, Object { "x": 1607437200000, - "y": 46937.5, + "y": 47167, }, Object { "x": 1607437260000, @@ -215,15 +215,15 @@ Array [ }, Object { "x": 1607436780000, - "y": 69429, + "y": 69631, }, Object { "x": 1607436840000, - "y": 8071285, + "y": 8093695, }, Object { "x": 1607436900000, - "y": 31949, + "y": 31999, }, Object { "x": 1607436960000, @@ -231,7 +231,7 @@ Array [ }, Object { "x": 1607437020000, - "y": 47755, + "y": 47871, }, Object { "x": 1607437080000, @@ -239,7 +239,7 @@ Array [ }, Object { "x": 1607437140000, - "y": 35403, + "y": 35519, }, Object { "x": 1607437200000, @@ -255,7 +255,7 @@ Array [ }, Object { "x": 1607437380000, - "y": 48137, + "y": 48255, }, Object { "x": 1607437440000, @@ -263,7 +263,7 @@ Array [ }, Object { "x": 1607437500000, - "y": 35457, + "y": 35583, }, Object { "x": 1607437560000, @@ -357,7 +357,7 @@ Array [ }, Object { "x": 1607436840000, - "y": 2, + "y": 1, }, Object { "x": 1607436900000, @@ -377,7 +377,7 @@ Array [ }, Object { "x": 1607437140000, - "y": 4, + "y": 1, }, Object { "x": 1607437200000, @@ -422,15 +422,15 @@ Array [ }, Object { "x": 1607435880000, - "y": 69429, + "y": 69631, }, Object { "x": 1607435940000, - "y": 8071285, + "y": 8093695, }, Object { "x": 1607436000000, - "y": 31949, + "y": 31999, }, Object { "x": 1607436060000, @@ -438,7 +438,7 @@ Array [ }, Object { "x": 1607436120000, - "y": 47755, + "y": 47871, }, Object { "x": 1607436180000, @@ -446,7 +446,7 @@ Array [ }, Object { "x": 1607436240000, - "y": 35403, + "y": 35519, }, Object { "x": 1607436300000, @@ -462,7 +462,7 @@ Array [ }, Object { "x": 1607436480000, - "y": 48137, + "y": 48255, }, Object { "x": 1607436540000, @@ -470,7 +470,7 @@ Array [ }, Object { "x": 1607436600000, - "y": 35457, + "y": 35583, }, Object { "x": 1607436660000, @@ -494,7 +494,7 @@ Array [ }, Object { "x": 1607436960000, - "y": 30501, + "y": 30527, }, Object { "x": 1607437020000, @@ -510,7 +510,7 @@ Array [ }, Object { "x": 1607437200000, - "y": 46937.5, + "y": 47167, }, Object { "x": 1607437260000, @@ -555,7 +555,7 @@ Array [ }, Object { "x": 1607435940000, - "y": 2, + "y": 1, }, Object { "x": 1607436000000, @@ -575,7 +575,7 @@ Array [ }, Object { "x": 1607436240000, - "y": 4, + "y": 1, }, Object { "x": 1607436300000, @@ -809,15 +809,15 @@ Array [ }, Object { "x": 1607435880000, - "y": 69429, + "y": 69631, }, Object { "x": 1607435940000, - "y": 8198285, + "y": 8224767, }, Object { "x": 1607436000000, - "y": 31949, + "y": 31999, }, Object { "x": 1607436060000, @@ -825,7 +825,7 @@ Array [ }, Object { "x": 1607436120000, - "y": 47755, + "y": 47871, }, Object { "x": 1607436180000, @@ -833,7 +833,7 @@ Array [ }, Object { "x": 1607436240000, - "y": 73411, + "y": 73727, }, Object { "x": 1607436300000, @@ -849,7 +849,7 @@ Array [ }, Object { "x": 1607436480000, - "y": 55116, + "y": 55295, }, Object { "x": 1607436540000, @@ -857,7 +857,7 @@ Array [ }, Object { "x": 1607436600000, - "y": 35457, + "y": 35583, }, Object { "x": 1607436660000, @@ -881,7 +881,7 @@ Array [ }, Object { "x": 1607436960000, - "y": 46040, + "y": 46079, }, Object { "x": 1607437020000, @@ -897,7 +897,7 @@ Array [ }, Object { "x": 1607437200000, - "y": 82486, + "y": 82943, }, Object { "x": 1607437260000, diff --git a/x-pack/test/apm_api_integration/tests/transactions/error_rate.ts b/x-pack/test/apm_api_integration/tests/transactions/error_rate.ts index ce16ad2c96c3b..7a54d616e0316 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/error_rate.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/error_rate.ts @@ -101,7 +101,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { new Date( first(errorRateResponse.currentPeriod.transactionErrorRate)?.x ?? NaN ).toISOString() - ).toMatchInline(`"2020-12-08T13:57:30.000Z"`); + ).toMatchInline(`"2020-12-08T13:57:00.000Z"`); }); it('has the correct end date', () => { @@ -109,17 +109,19 @@ export default function ApiTest({ getService }: FtrProviderContext) { new Date( last(errorRateResponse.currentPeriod.transactionErrorRate)?.x ?? NaN ).toISOString() - ).toMatchInline(`"2020-12-08T14:27:30.000Z"`); + ).toMatchInline(`"2020-12-08T14:27:00.000Z"`); }); it('has the correct number of buckets', () => { expectSnapshot(errorRateResponse.currentPeriod.transactionErrorRate.length).toMatchInline( - `61` + `31` ); }); it('has the correct calculation for average', () => { - expectSnapshot(errorRateResponse.currentPeriod.average).toMatchInline(`0.16`); + expectSnapshot(errorRateResponse.currentPeriod.average).toMatchInline( + `0.159420289855072` + ); }); it('has the correct error rate', () => { @@ -170,12 +172,12 @@ export default function ApiTest({ getService }: FtrProviderContext) { new Date( first(errorRateResponse.currentPeriod.transactionErrorRate)?.x ?? NaN ).toISOString() - ).toMatchInline(`"2020-12-08T14:12:50.000Z"`); + ).toMatchInline(`"2020-12-08T14:12:00.000Z"`); expectSnapshot( new Date( first(errorRateResponse.previousPeriod.transactionErrorRate)?.x ?? NaN ).toISOString() - ).toMatchInline(`"2020-12-08T14:12:50.000Z"`); + ).toMatchInline(`"2020-12-08T14:12:00.000Z"`); }); it('has the correct end date', () => { @@ -183,30 +185,28 @@ export default function ApiTest({ getService }: FtrProviderContext) { new Date( last(errorRateResponse.currentPeriod.transactionErrorRate)?.x ?? NaN ).toISOString() - ).toMatchInline(`"2020-12-08T14:27:50.000Z"`); + ).toMatchInline(`"2020-12-08T14:27:00.000Z"`); expectSnapshot( new Date( last(errorRateResponse.previousPeriod.transactionErrorRate)?.x ?? NaN ).toISOString() - ).toMatchInline(`"2020-12-08T14:27:50.000Z"`); + ).toMatchInline(`"2020-12-08T14:27:00.000Z"`); }); it('has the correct number of buckets', () => { expectSnapshot(errorRateResponse.currentPeriod.transactionErrorRate.length).toMatchInline( - `91` + `16` ); expectSnapshot( errorRateResponse.previousPeriod.transactionErrorRate.length - ).toMatchInline(`91`); + ).toMatchInline(`16`); }); it('has the correct calculation for average', () => { expectSnapshot(errorRateResponse.currentPeriod.average).toMatchInline( - `0.233333333333333` - ); - expectSnapshot(errorRateResponse.previousPeriod.average).toMatchInline( - `0.111111111111111` + `0.206896551724138` ); + expectSnapshot(errorRateResponse.previousPeriod.average).toMatchInline(`0.125`); }); it('has the correct error rate', () => { diff --git a/x-pack/test/apm_api_integration/tests/transactions/latency.ts b/x-pack/test/apm_api_integration/tests/transactions/latency.ts index 13167f473e06a..1dc521e388b0b 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/latency.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/latency.ts @@ -110,7 +110,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(response.status).to.be(200); const latencyChartReturn = response.body as LatencyChartReturnType; expect(latencyChartReturn.currentPeriod.overallAvgDuration).not.to.be(null); - expect(latencyChartReturn.currentPeriod.latencyTimeseries.length).to.be.eql(61); + expect(latencyChartReturn.currentPeriod.latencyTimeseries.length).to.be.eql(31); }); }); @@ -134,7 +134,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(response.status).to.be(200); const latencyChartReturn = response.body as LatencyChartReturnType; expect(latencyChartReturn.currentPeriod.overallAvgDuration).not.to.be(null); - expect(latencyChartReturn.currentPeriod.latencyTimeseries.length).to.be.eql(61); + expect(latencyChartReturn.currentPeriod.latencyTimeseries.length).to.be.eql(31); }); }); @@ -160,10 +160,10 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(latencyChartReturn.currentPeriod.overallAvgDuration).not.to.be(null); expectSnapshot(latencyChartReturn.currentPeriod.overallAvgDuration).toMatchInline( - `24920.1052631579` + `24989.3157894737` ); - expect(latencyChartReturn.currentPeriod.latencyTimeseries.length).to.be.eql(61); + expect(latencyChartReturn.currentPeriod.latencyTimeseries.length).to.be.eql(31); }); }); diff --git a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_detailed_statistics.ts b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_detailed_statistics.ts index 303b8f715e957..5417a5a811db8 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_detailed_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_detailed_statistics.ts @@ -280,8 +280,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { const currentPeriodFirstItem = currentPeriodItems[0]; const previousPeriodFirstItem = previousPeriodItems[0]; - expectSnapshot(roundNumber(currentPeriodFirstItem.impact)).toMatchInline(`"21.75"`); - expectSnapshot(roundNumber(previousPeriodFirstItem.impact)).toMatchInline(`"96.94"`); + expectSnapshot(roundNumber(currentPeriodFirstItem.impact)).toMatchInline(`"21.29"`); + expectSnapshot(roundNumber(previousPeriodFirstItem.impact)).toMatchInline(`"97.03"`); }); }); } diff --git a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_main_statistics.ts b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_main_statistics.ts index a2da077864b99..63281d405efdd 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_main_statistics.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/transactions_groups_main_statistics.ts @@ -77,9 +77,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { "APIRestController#customer", "ResourceHttpRequestHandler", "APIRestController#customers", - "APIRestController#stats", "APIRestController#topProducts", "APIRestController#orders", + "APIRestController#stats", "APIRestController#product", "APIRestController#products", "DispatcherServlet#doPost", @@ -91,18 +91,18 @@ export default function ApiTest({ getService }: FtrProviderContext) { ); expectSnapshot(impacts).toMatchInline(` Array [ - 93.9295870910491, - 0.850308244392878, - 0.905514602241759, - 0.699947181217412, - 0.143906183235671, - 1.35334507158962, - 0.860178761411346, - 0.476138685202191, - 0.446650726277923, - 0.262571482598846, - 0.062116281544223, - 0.00973568923904662, + 93.9315487787012, + 0.850246601543056, + 0.904925560144193, + 0.69948730072783, + 0.144008466274819, + 1.35206610551638, + 0.476127116253573, + 0.446552298379043, + 0.860493303928453, + 0.262800744776717, + 0.0620236424870074, + 0.00972008126772269, ] `); @@ -113,11 +113,11 @@ export default function ApiTest({ getService }: FtrProviderContext) { expectSnapshot(pick(firstItem, 'name', 'latency', 'throughput', 'errorRate', 'impact')) .toMatchInline(` Object { - "errorRate": 0.0625, - "impact": 93.9295870910491, - "latency": 1044995.1875, + "errorRate": 0.0833333333333333, + "impact": 93.9315487787012, + "latency": 1047903, "name": "DispatcherServlet#doGet", - "throughput": 0.533333333333333, + "throughput": 0.4, } `); }); @@ -140,7 +140,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { const transctionsGroupsPrimaryStatistics = response.body as TransactionsGroupsPrimaryStatistics; const firstItem = transctionsGroupsPrimaryStatistics.transactionGroups[0]; - expectSnapshot(firstItem.latency).toMatchInline(`8198285`); + expectSnapshot(firstItem.latency).toMatchInline(`8224767`); }); } ); diff --git a/x-pack/test/functional/apps/lens/chart_data.ts b/x-pack/test/functional/apps/lens/chart_data.ts index 5951260c8704c..87147f3d8ae05 100644 --- a/x-pack/test/functional/apps/lens/chart_data.ts +++ b/x-pack/test/functional/apps/lens/chart_data.ts @@ -45,6 +45,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { { x: 'Other', y: 5722.77 }, ]; + const expectedPieData = [ + { name: '97.220.3.248', value: 19755 }, + { name: '169.228.188.120', value: 18994 }, + { name: '78.83.247.30', value: 17246 }, + { name: '226.82.228.233', value: 15687 }, + { name: '93.28.27.24', value: 15614.33 }, + { name: '__other__', value: 5722.77 }, + ]; + function assertMatchesExpectedData(state: DebugState) { expect( state.bars![0].bars.map((bar) => ({ @@ -54,32 +63,41 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ).to.eql(expectedData); } + function assertMatchesExpectedPieData(state: DebugState) { + expect( + state + .partition![0].partitions.map((partition) => ({ + name: partition.name, + value: Math.floor(partition.value * 100) / 100, + })) + .sort(({ value: a }, { value: b }) => b - a) + ).to.eql(expectedPieData); + } + it('should render xy chart', async () => { const data = await PageObjects.lens.getCurrentChartDebugState(); assertMatchesExpectedData(data!); }); - // Partition chart tests have to be skipped until - // https://github.com/elastic/elastic-charts/issues/917 gets fixed - it.skip('should render pie chart', async () => { + it('should render pie chart', async () => { await PageObjects.lens.switchToVisualization('pie'); await PageObjects.lens.waitForVisualization(); const data = await PageObjects.lens.getCurrentChartDebugState(); - assertMatchesExpectedData(data!); + assertMatchesExpectedPieData(data!); }); - it.skip('should render donut chart', async () => { + it('should render donut chart', async () => { await PageObjects.lens.switchToVisualization('donut'); await PageObjects.lens.waitForVisualization(); const data = await PageObjects.lens.getCurrentChartDebugState(); - assertMatchesExpectedData(data!); + assertMatchesExpectedPieData(data!); }); - it.skip('should render treemap chart', async () => { + it('should render treemap chart', async () => { await PageObjects.lens.switchToVisualization('treemap', 'treemap'); await PageObjects.lens.waitForVisualization(); const data = await PageObjects.lens.getCurrentChartDebugState(); - assertMatchesExpectedData(data!); + assertMatchesExpectedPieData(data!); }); it('should render heatmap chart', async () => { diff --git a/x-pack/test/functional/apps/ml/anomaly_detection/annotations.ts b/x-pack/test/functional/apps/ml/anomaly_detection/annotations.ts index b6d23f1c1a3ea..a6ea27be21cc8 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection/annotations.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection/annotations.ts @@ -6,35 +6,7 @@ */ import { FtrProviderContext } from '../../../ftr_provider_context'; -import { Job, Datafeed } from '../../../../../plugins/ml/common/types/anomaly_detection_jobs'; - -// @ts-expect-error doesn't implement the full interface -const JOB_CONFIG: Job = { - job_id: `fq_single_1_smv`, - description: 'mean(responsetime) on farequote dataset with 15m bucket span', - groups: ['farequote', 'automated', 'single-metric'], - analysis_config: { - bucket_span: '15m', - influencers: [], - detectors: [ - { - function: 'mean', - field_name: 'responsetime', - }, - ], - }, - data_description: { time_field: '@timestamp' }, - analysis_limits: { model_memory_limit: '10mb' }, - model_plot_config: { enabled: true }, -}; - -// @ts-expect-error doesn't implement the full interface -const DATAFEED_CONFIG: Datafeed = { - datafeed_id: 'datafeed-fq_single_1_smv', - indices: ['ft_farequote'], - job_id: 'fq_single_1_smv', - query: { bool: { must: [{ match_all: {} }] } }, -}; +import { Annotation } from '../../../../../plugins/ml/common/types/annotations'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); @@ -42,15 +14,34 @@ export default function ({ getService }: FtrProviderContext) { describe('annotations', function () { this.tags(['mlqa']); + const jobId = `fq_single_1_smv_${Date.now()}`; + + const annotation = { + timestamp: 1455142431586, + end_timestamp: 1455200689604, + annotation: 'Test annotation', + job_id: jobId, + type: 'annotation' as Annotation['type'], + detector_index: 0, + event: 'user', + create_time: 1626129498464, + create_username: 'user1', + modified_time: 1626129498464, + modified_username: 'user2', + }; + before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/farequote'); await ml.testResources.createIndexPatternIfNeeded('ft_farequote', '@timestamp'); await ml.testResources.setKibanaTimeZoneToUTC(); + const JOB_CONFIG = ml.commonConfig.getADFqSingleMetricJobConfig(jobId); + const DATAFEED_CONFIG = ml.commonConfig.getADFqDatafeedConfig(jobId); + await ml.api.createAndRunAnomalyDetectionLookbackJob(JOB_CONFIG, DATAFEED_CONFIG); + // Points the read/write aliases of annotations to an index with wrong mappings // so we can simulate errors when requesting annotations. - await ml.testResources.setupBrokenAnnotationsIndexState(JOB_CONFIG.job_id); await ml.securityUI.loginAsMlPowerUser(); }); @@ -58,45 +49,245 @@ export default function ({ getService }: FtrProviderContext) { await ml.api.cleanMlIndices(); }); - it('displays error on broken annotation index and recovers after fix', async () => { - await ml.testExecution.logTestStep('loads from job list row link'); - await ml.navigation.navigateToMl(); - await ml.navigation.navigateToJobManagement(); + describe('creating', function () { + const newText = 'Created annotation text'; + + it('creates annotation', async () => { + await ml.testExecution.logTestStep('loads from job list row link'); + await ml.navigation.navigateToMl(); + await ml.navigation.navigateToJobManagement(); + + await ml.jobTable.waitForJobsToLoad(); + await ml.jobTable.filterWithSearchString(jobId, 1); + + await ml.jobTable.clickOpenJobInSingleMetricViewerButton(jobId); + await ml.commonUI.waitForMlLoadingIndicatorToDisappear(); + + await ml.singleMetricViewer.assertAnnotationsExists('loaded'); + + await ml.testExecution.logTestStep('creates new annotation'); + await ml.jobAnnotations.createAnnotation(newText); + + await ml.testExecution.logTestStep('displays newly created annotation'); + await ml.jobAnnotations.ensureSingleMetricViewerAnnotationsPanelOpen(); + await ml.jobAnnotations.assertAnnotationExists({ + annotation: newText, + event: 'user', + }); + }); + + it('displays newly created annotation in anomaly explorer and job list', async () => { + await ml.testExecution.logTestStep('should display created annotation in anomaly explorer'); + await ml.navigation.navigateToAnomalyExplorerViaSingleMetricViewer(); + await ml.anomalyExplorer.assertAnnotationsPanelExists('loaded'); + + await ml.jobAnnotations.ensureAnomalyExplorerAnnotationsPanelOpen(); + await ml.jobAnnotations.assertAnnotationExists({ + annotation: newText, + event: 'user', + }); + + await ml.testExecution.logTestStep('should display created annotation in job list'); + await ml.navigation.navigateToJobManagement(); + await ml.jobTable.waitForJobsToLoad(); + await ml.jobTable.filterWithSearchString(jobId, 1); + await ml.jobTable.openAnnotationsTab(jobId); + await ml.jobAnnotations.assertAnnotationExists({ + annotation: newText, + event: 'user', + }); + }); + }); + + describe('editing', function () { + const annotationId = `edit-annotation-id-${Date.now()}`; + const newText = 'Edited annotation text'; + const expectedOriginalAnnotation = { + annotation: annotation.annotation, + from: '2016-02-10 22:13:51', + to: '2016-02-11 14:24:49', + modifiedTime: '2021-07-12 22:38:18', + modifiedBy: annotation.modified_username, + event: annotation.event, + }; + const expectedEditedAnnotation = { + annotation: newText, + event: annotation.event, + }; + + before(async () => { + await ml.api.indexAnnotation(annotation, annotationId); + }); + + it('displays the original annotation correctly', async () => { + await ml.testExecution.logTestStep('loads from job list row link'); + await ml.navigation.navigateToMl(); + await ml.navigation.navigateToJobManagement(); + + await ml.jobTable.waitForJobsToLoad(); + await ml.jobTable.filterWithSearchString(jobId, 1); + await ml.jobTable.openAnnotationsTab(jobId); + await ml.jobAnnotations.assertAnnotationContentById( + annotationId, + expectedOriginalAnnotation + ); + + await ml.jobTable.clickOpenJobInSingleMetricViewerButton(jobId); + await ml.commonUI.waitForMlLoadingIndicatorToDisappear(); + await ml.singleMetricViewer.assertAnnotationsExists('loaded'); + + await ml.testExecution.logTestStep('displays annotation content'); + await ml.jobAnnotations.ensureSingleMetricViewerAnnotationsPanelOpen(); + await ml.jobAnnotations.assertAnnotationsRowExists(annotationId); + await ml.jobAnnotations.assertAnnotationContentById( + annotationId, + expectedOriginalAnnotation + ); + }); + + it('edits the annotation', async () => { + await ml.testExecution.logTestStep('opens edit annotation flyout'); + await ml.jobAnnotations.clickAnnotationsEditAction(annotationId); + + await ml.testExecution.logTestStep('displays annotation content'); + await ml.jobAnnotations.assertAnnotationsEditFlyoutContent({ + 'Job ID': jobId, + Start: 'February 10th 2016, 22:13:51', + End: 'February 11th 2016, 14:24:49', + Created: 'July 12th 2021, 22:38:18', + 'Created by': annotation.create_username, + 'Last modified': 'July 12th 2021, 22:38:18', + 'Modified by': annotation.modified_username, + Detector: 'mean(responsetime)', + }); + + await ml.testExecution.logTestStep('edits and saves new annotation text'); + await ml.jobAnnotations.setAnnotationText(newText); + + await ml.testExecution.logTestStep('displays annotation with newly edited text'); + await ml.jobAnnotations.assertAnnotationContentById(annotationId, expectedEditedAnnotation); + }); + + it('displays newly edited annotation in anomaly explorer and job list', async () => { + await ml.testExecution.logTestStep('should display edited annotation in anomaly explorer'); + await ml.navigation.navigateToAnomalyExplorerViaSingleMetricViewer(); + await ml.anomalyExplorer.assertAnnotationsPanelExists('loaded'); + + await ml.jobAnnotations.ensureAnomalyExplorerAnnotationsPanelOpen(); + await ml.jobAnnotations.assertAnnotationContentById(annotationId, expectedEditedAnnotation); + + await ml.testExecution.logTestStep('should display edited annotation in job list'); + await ml.navigation.navigateToJobManagement(); + await ml.jobTable.waitForJobsToLoad(); + await ml.jobTable.filterWithSearchString(jobId, 1); + await ml.jobTable.openAnnotationsTab(jobId); + await ml.jobAnnotations.assertAnnotationContentById(annotationId, expectedEditedAnnotation); + }); + }); + + describe('deleting', function () { + const annotationId = `delete-annotation-id-${Date.now()}`; + + before(async () => { + await ml.api.indexAnnotation(annotation, annotationId); + }); + + it('displays the original annotation', async () => { + await ml.testExecution.logTestStep('loads from job list row link'); + await ml.navigation.navigateToMl(); + await ml.navigation.navigateToJobManagement(); + + await ml.jobTable.waitForJobsToLoad(); + await ml.jobTable.filterWithSearchString(jobId, 1); + + await ml.jobTable.clickOpenJobInSingleMetricViewerButton(jobId); + await ml.commonUI.waitForMlLoadingIndicatorToDisappear(); + await ml.singleMetricViewer.assertAnnotationsExists('loaded'); + + await ml.testExecution.logTestStep('displays annotation content'); + await ml.jobAnnotations.ensureSingleMetricViewerAnnotationsPanelOpen(); + await ml.jobAnnotations.assertAnnotationsRowExists(annotationId); + await ml.jobAnnotations.assertAnnotationContentById(annotationId, { + annotation: annotation.annotation, + from: '2016-02-10 22:13:51', + to: '2016-02-11 14:24:49', + modifiedTime: '2021-07-12 22:38:18', + modifiedBy: annotation.modified_username, + event: annotation.event, + }); + }); + + it('deletes the annotation', async () => { + await ml.jobAnnotations.deleteAnnotation(annotationId); + await ml.jobAnnotations.assertAnnotationsRowMissing(annotationId); + }); + + it('does not display the deleted annotation in anomaly explorer and job list', async () => { + await ml.testExecution.logTestStep( + 'does not show the deleted annotation in anomaly explorer' + ); + await ml.navigation.navigateToAnomalyExplorerViaSingleMetricViewer(); + await ml.anomalyExplorer.assertAnnotationsPanelExists('loaded'); + await ml.jobAnnotations.ensureAnomalyExplorerAnnotationsPanelOpen(); + await ml.jobAnnotations.assertAnnotationsRowMissing(annotationId); + + await ml.testExecution.logTestStep('does not show the deleted annotation in job list'); + await ml.navigation.navigateToJobManagement(); + await ml.jobTable.waitForJobsToLoad(); + await ml.jobTable.filterWithSearchString(jobId, 1); + await ml.jobTable.openAnnotationsTab(jobId); + await ml.jobAnnotations.assertAnnotationsRowMissing(annotationId); + }); + }); - await ml.jobTable.waitForJobsToLoad(); - await ml.jobTable.filterWithSearchString(JOB_CONFIG.job_id, 1); + describe('with errors', function () { + before(async () => { + // Points the read/write aliases of annotations to an index with wrong mappings + // so we can simulate errors when requesting annotations. + await ml.testResources.setupBrokenAnnotationsIndexState(jobId); + }); - await ml.jobTable.clickOpenJobInSingleMetricViewerButton(JOB_CONFIG.job_id); - await ml.commonUI.waitForMlLoadingIndicatorToDisappear(); + it('displays error on broken annotation index and recovers after fix', async () => { + await ml.testExecution.logTestStep('loads from job list row link'); + await ml.navigation.navigateToMl(); + await ml.navigation.navigateToJobManagement(); - await ml.testExecution.logTestStep('pre-fills the job selection'); - await ml.jobSelection.assertJobSelection([JOB_CONFIG.job_id]); + await ml.jobTable.waitForJobsToLoad(); + await ml.jobTable.filterWithSearchString(jobId, 1); - await ml.testExecution.logTestStep('pre-fills the detector input'); - await ml.singleMetricViewer.assertDetectorInputExist(); - await ml.singleMetricViewer.assertDetectorInputValue('0'); + await ml.jobTable.clickOpenJobInSingleMetricViewerButton(jobId); + await ml.commonUI.waitForMlLoadingIndicatorToDisappear(); - await ml.testExecution.logTestStep('should display the annotations section showing an error'); - await ml.singleMetricViewer.assertAnnotationsExists('error'); + await ml.testExecution.logTestStep( + 'should display the annotations section showing an error' + ); + await ml.singleMetricViewer.assertAnnotationsExists('error'); - await ml.testExecution.logTestStep('should navigate to anomaly explorer'); - await ml.navigation.navigateToAnomalyExplorerViaSingleMetricViewer(); + await ml.testExecution.logTestStep('should navigate to anomaly explorer'); + await ml.navigation.navigateToAnomalyExplorerViaSingleMetricViewer(); - await ml.testExecution.logTestStep('should display the annotations section showing an error'); - await ml.anomalyExplorer.assertAnnotationsPanelExists('error'); + await ml.testExecution.logTestStep( + 'should display the annotations section showing an error' + ); + await ml.anomalyExplorer.assertAnnotationsPanelExists('error'); - await ml.testExecution.logTestStep('should display the annotations section without an error'); - // restores the aliases to point to the original working annotations index - // so we can run tests against successfully loaded annotations sections. - await ml.testResources.restoreAnnotationsIndexState(); - await ml.anomalyExplorer.refreshPage(); - await ml.anomalyExplorer.assertAnnotationsPanelExists('loaded'); + await ml.testExecution.logTestStep( + 'should display the annotations section without an error' + ); + // restores the aliases to point to the original working annotations index + // so we can run tests against successfully loaded annotations sections. + await ml.testResources.restoreAnnotationsIndexState(); + await ml.anomalyExplorer.refreshPage(); + await ml.anomalyExplorer.assertAnnotationsPanelExists('loaded'); - await ml.testExecution.logTestStep('should navigate to single metric viewer'); - await ml.navigation.navigateToSingleMetricViewerViaAnomalyExplorer(); + await ml.testExecution.logTestStep('should navigate to single metric viewer'); + await ml.navigation.navigateToSingleMetricViewerViaAnomalyExplorer(); - await ml.testExecution.logTestStep('should display the annotations section without an error'); - await ml.singleMetricViewer.assertAnnotationsExists('loaded'); + await ml.testExecution.logTestStep( + 'should display the annotations section without an error' + ); + await ml.singleMetricViewer.assertAnnotationsExists('loaded'); + }); }); }); } diff --git a/x-pack/test/functional/apps/ml/data_frame_analytics/feature_importance.ts b/x-pack/test/functional/apps/ml/data_frame_analytics/feature_importance.ts index fbd6cc70418d3..91d7b0a9347e2 100644 --- a/x-pack/test/functional/apps/ml/data_frame_analytics/feature_importance.ts +++ b/x-pack/test/functional/apps/ml/data_frame_analytics/feature_importance.ts @@ -183,7 +183,8 @@ export default function ({ getService }: FtrProviderContext) { }); for (const testData of testDataList) { - describe(`${testData.suiteTitle}`, function () { + // FLAKY: https://github.com/elastic/kibana/issues/93188 + describe.skip(`${testData.suiteTitle}`, function () { before(async () => { await ml.navigation.navigateToMl(); await ml.navigation.navigateToDataFrameAnalytics(); diff --git a/x-pack/test/functional/services/ml/api.ts b/x-pack/test/functional/services/ml/api.ts index ec5ca4c661157..a3b77655f28e1 100644 --- a/x-pack/test/functional/services/ml/api.ts +++ b/x-pack/test/functional/services/ml/api.ts @@ -845,17 +845,18 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { return undefined; }, - async indexAnnotation(annotationRequestBody: Partial) { + async indexAnnotation(annotationRequestBody: Partial, id?: string) { log.debug(`Indexing annotation '${JSON.stringify(annotationRequestBody)}'...`); // @ts-ignore due to outdated type for IndexDocumentParams.type const params = { index: ML_ANNOTATIONS_INDEX_ALIAS_WRITE, + id, body: annotationRequestBody, refresh: 'wait_for', } as const; const { body } = await es.index(params); await this.waitForAnnotationToExist(body._id); - log.debug('> Annotation indexed.'); + log.debug(`> Annotation ${body._id} indexed.`); return body; }, diff --git a/x-pack/test/functional/services/ml/index.ts b/x-pack/test/functional/services/ml/index.ts index 2cc9a3afa442b..e269d408cf7d0 100644 --- a/x-pack/test/functional/services/ml/index.ts +++ b/x-pack/test/functional/services/ml/index.ts @@ -50,6 +50,7 @@ import { SwimLaneProvider } from './swim_lane'; import { MachineLearningDashboardJobSelectionTableProvider } from './dashboard_job_selection_table'; import { MachineLearningDashboardEmbeddablesProvider } from './dashboard_embeddables'; import { TrainedModelsProvider } from './trained_models'; +import { MachineLearningJobAnnotationsProvider } from './job_annotations_table'; export function MachineLearningProvider(context: FtrProviderContext) { const commonAPI = MachineLearningCommonAPIProvider(context); @@ -92,6 +93,7 @@ export function MachineLearningProvider(context: FtrProviderContext) { dataVisualizerTable ); + const jobAnnotations = MachineLearningJobAnnotationsProvider(context); const jobManagement = MachineLearningJobManagementProvider(context, api); const jobSelection = MachineLearningJobSelectionProvider(context); const jobSourceSelection = MachineLearningJobSourceSelectionProvider(context); @@ -138,6 +140,7 @@ export function MachineLearningProvider(context: FtrProviderContext) { dataVisualizerIndexBased, dataVisualizerIndexPatternManagement, dataVisualizerTable, + jobAnnotations, jobManagement, jobSelection, jobSourceSelection, diff --git a/x-pack/test/functional/services/ml/job_annotations_table.ts b/x-pack/test/functional/services/ml/job_annotations_table.ts new file mode 100644 index 0000000000000..99e25c20573ae --- /dev/null +++ b/x-pack/test/functional/services/ml/job_annotations_table.ts @@ -0,0 +1,345 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export function MachineLearningJobAnnotationsProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + const find = getService('find'); + const browser = getService('browser'); + + return new (class MlJobAnnotations { + public async parseJobAnnotationTable() { + const table = await testSubjects.find('~mlAnnotationsTable'); + const $ = await table.parseDomContent(); + const rows = []; + + for (const tr of $.findTestSubjects('~mlAnnotationsTableRow').toArray()) { + const $tr = $(tr); + + rows.push({ + annotation: $tr + .findTestSubject('mlAnnotationsColumnAnnotation') + .find('.euiTableCellContent') + .text() + .trim(), + from: $tr + .findTestSubject('mlAnnotationsColumnFrom') + .find('.euiTableCellContent') + .text() + .trim(), + to: $tr + .findTestSubject('mlAnnotationsColumnTo') + .find('.euiTableCellContent') + .text() + .trim(), + modifiedTime: $tr + .findTestSubject('mlAnnotationsColumnModifiedDate') + .find('.euiTableCellContent') + .text() + .trim(), + modifiedBy: $tr + .findTestSubject('mlAnnotationsColumnModifiedBy') + .find('.euiTableCellContent') + .text() + .trim(), + event: $tr + .findTestSubject('mlAnnotationsColumnEvent') + .find('.euiTableCellContent') + .text() + .trim(), + }); + } + + return rows; + } + + public async parseJobAnnotationTableRow(annotationId: string) { + const table = await testSubjects.find('~mlAnnotationsTable'); + const $ = await table.parseDomContent(); + const rows = []; + + for (const tr of $.findTestSubjects(`~row-${annotationId}`).toArray()) { + const $tr = $(tr); + + rows.push({ + annotation: $tr + .findTestSubject('mlAnnotationsColumnAnnotation') + .find('.euiTableCellContent') + .text() + .trim(), + from: $tr + .findTestSubject('mlAnnotationsColumnFrom') + .find('.euiTableCellContent') + .text() + .trim(), + to: $tr + .findTestSubject('mlAnnotationsColumnTo') + .find('.euiTableCellContent') + .text() + .trim(), + modifiedTime: $tr + .findTestSubject('mlAnnotationsColumnModifiedDate') + .find('.euiTableCellContent') + .text() + .trim(), + modifiedBy: $tr + .findTestSubject('mlAnnotationsColumnModifiedBy') + .find('.euiTableCellContent') + .text() + .trim(), + event: $tr + .findTestSubject('mlAnnotationsColumnEvent') + .find('.euiTableCellContent') + .text() + .trim(), + }); + } + + return rows[0]; + } + + public rowSelector(annotationId: string, subSelector?: string) { + const row = `~mlAnnotationsTable > ~row-${annotationId}`; + return !subSelector ? row : `${row} > ${subSelector}`; + } + + public async ensureSingleMetricViewerAnnotationsPanelOpen() { + await retry.tryForTime(10000, async () => { + if (!(await testSubjects.exists('mlAnnotationsTable'))) { + await testSubjects.click('mlAnomalyExplorerAnnotations loaded'); + await testSubjects.existOrFail('mlAnnotationsTable'); + } + }); + } + + public async ensureAnomalyExplorerAnnotationsPanelOpen() { + await retry.tryForTime(10000, async () => { + if (!(await testSubjects.exists('mlAnnotationsTable'))) { + await testSubjects.click('mlAnomalyExplorerAnnotationsPanelButton'); + await testSubjects.existOrFail('mlAnnotationsTable'); + } + }); + } + + public async assertAnnotationsTableExists() { + await retry.tryForTime(1000, async () => { + await testSubjects.existOrFail('mlAnnotationsTable'); + }); + } + + public async assertAnnotationsRowExists(annotationId: string) { + await retry.tryForTime(1000, async () => { + await testSubjects.existOrFail(this.rowSelector(annotationId)); + }); + } + + public async assertAnnotationsRowMissing(annotationId: string) { + await retry.tryForTime(1000, async () => { + await testSubjects.missingOrFail(this.rowSelector(annotationId)); + }); + } + + public async assertAnnotationContentById( + annotationId: string, + expectedEntries: Record + ) { + await this.assertAnnotationsTableExists(); + await this.assertAnnotationsRowExists(annotationId); + + await retry.tryForTime(30 * 1000, async () => { + const parsedRow = await this.parseJobAnnotationTableRow(annotationId); + for (const [key, value] of Object.entries(expectedEntries)) { + expect(parsedRow) + .to.have.property(key) + .eql( + value, + `Expected annotation row ${annotationId} to have '${key}' with value '${value}'` + ); + } + }); + } + + public async assertAnnotationExists(expectedEntries: Record<'annotation' | string, string>) { + await this.assertAnnotationsTableExists(); + + await retry.tryForTime(30 * 1000, async () => { + const parsedTable = await this.parseJobAnnotationTable(); + const parsedRow = parsedTable.find((t) => t.annotation === expectedEntries.annotation); + expect(parsedRow).to.be.ok(); + for (const [key, value] of Object.entries(expectedEntries)) { + expect(parsedRow) + .to.have.property(key) + .eql(value, `Expected annotation table to have '${key}' with value '${value}'`); + } + }); + } + + public async assertAnnotationsEditActionExists(annotationId: string) { + await retry.tryForTime(1000, async () => { + await testSubjects.existOrFail(this.rowSelector(annotationId, 'mlAnnotationsActionEdit')); + }); + } + + public async clickAnnotationsEditAction(annotationId: string) { + await this.assertAnnotationsEditActionExists(annotationId); + await retry.tryForTime(1000, async () => { + await testSubjects.clickWhenNotDisabled( + this.rowSelector(annotationId, 'mlAnnotationsActionEdit') + ); + await testSubjects.existOrFail('mlAnnotationFlyout'); + await testSubjects.existOrFail('mlAnnotationFlyoutTitle'); + + const title = await testSubjects.getVisibleText('mlAnnotationFlyoutTitle'); + expect(title).to.eql( + 'Edit annotation', + `Expected annotations flyout title to be 'Edit annotation' but got ${title}` + ); + }); + } + + public async parseAnnotationFlyoutList() { + const table = await testSubjects.find('mlAnnotationDescriptionList'); + const $ = await table.parseDomContent(); + const dt = $('dt') + .toArray() + .map((key) => + $(key) + .text() + .replace(/ /g, '') + .trim() + ); + const dd = $('dd') + .toArray() + .map((key) => + $(key) + .text() + .replace(/ /g, '') + .trim() + ); + return Object.assign({}, ...dt.map((n, index) => ({ [n]: dd[index] }))); + } + + public async assertAnnotationsEditFlyoutContent(expectedEntries: Record) { + await retry.tryForTime(1000, async () => { + await testSubjects.existOrFail('mlAnnotationFlyout'); + await testSubjects.existOrFail('mlAnnotationsFlyoutTextInput'); + await testSubjects.existOrFail('mlAnnotationsFlyoutDeleteButton'); + await testSubjects.existOrFail('annotationFlyoutUpdateOrCreateButton'); + await testSubjects.existOrFail('mlAnnotationsFlyoutCancelButton'); + + const buttonTxt = await testSubjects.getVisibleText('annotationFlyoutUpdateOrCreateButton'); + expect(buttonTxt).to.eql( + 'Update', + `Expected annotations flyout button to be 'Update' but got ${buttonTxt}` + ); + + const parsedContent = await this.parseAnnotationFlyoutList(); + await retry.tryForTime(1000, async () => { + for (const [key, value] of Object.entries(parsedContent)) { + expect(expectedEntries) + .to.have.property(key) + .eql( + value, + `Expected annotations flyout description '${key}' to exist with value '${value}'` + ); + } + }); + }); + } + + public async setAnnotationText(text: string) { + await retry.tryForTime(1000, async () => { + await testSubjects.existOrFail(`mlAnnotationsFlyoutTextInput`); + await testSubjects.setValue(`mlAnnotationsFlyoutTextInput`, text, { + clearWithKeyboard: true, + }); + + await testSubjects.existOrFail('annotationFlyoutUpdateOrCreateButton'); + await testSubjects.click('annotationFlyoutUpdateOrCreateButton'); + await testSubjects.missingOrFail('mlAnnotationFlyout'); + }); + } + + public async deleteAnnotation(annotationId: string) { + await retry.tryForTime(1000, async () => { + await this.clickAnnotationsEditAction(annotationId); + await testSubjects.existOrFail('mlAnnotationFlyout'); + await testSubjects.existOrFail('mlAnnotationsFlyoutDeleteButton'); + await testSubjects.clickWhenNotDisabled('mlAnnotationsFlyoutDeleteButton'); + await testSubjects.existOrFail('mlAnnotationFlyoutConfirmDeleteModal'); + await testSubjects.clickWhenNotDisabled( + '~mlAnnotationFlyoutConfirmDeleteModal > ~confirmModalConfirmButton' + ); + }); + } + + public async openCreateAnnotationFlyout() { + await retry.tryForTime(30 * 1000, async () => { + const el = await find.byClassName('mlAnnotationBrush'); + + // simulate click and drag on the focus chart + // to generate annotation + await browser.dragAndDrop( + { + location: el, + offset: { + x: 0, + y: -100, + }, + }, + { + location: el, + offset: { + x: 100, + y: -100, + }, + } + ); + await testSubjects.existOrFail('mlAnnotationFlyout'); + }); + } + + public async assertAnnotationsCreateFlyoutContent(expectedEntries: Record) { + await retry.tryForTime(1000, async () => { + await testSubjects.existOrFail('mlAnnotationFlyout'); + await testSubjects.existOrFail('mlAnnotationsFlyoutTextInput'); + await testSubjects.existOrFail('annotationFlyoutUpdateOrCreateButton'); + await testSubjects.existOrFail('mlAnnotationsFlyoutCancelButton'); + + const buttonTxt = await testSubjects.getVisibleText('annotationFlyoutUpdateOrCreateButton'); + + expect(buttonTxt).to.eql( + 'Create', + `Expected annotations flyout button to be 'Create' but got ${buttonTxt}` + ); + + const parsedContent = await this.parseAnnotationFlyoutList(); + await retry.tryForTime(1000, async () => { + for (const [key, value] of Object.entries(parsedContent)) { + expect(expectedEntries) + .to.have.property(key) + .eql( + value, + `Expected annotations flyout description '${key}' to exist with value '${value}'` + ); + } + }); + }); + } + + public async createAnnotation(text: string) { + await retry.tryForTime(30 * 1000, async () => { + await this.openCreateAnnotationFlyout(); + await this.setAnnotationText(text); + }); + } + })(); +} diff --git a/x-pack/test/functional/services/ml/job_table.ts b/x-pack/test/functional/services/ml/job_table.ts index a39e62d6281fe..46cb0ea5527ca 100644 --- a/x-pack/test/functional/services/ml/job_table.ts +++ b/x-pack/test/functional/services/ml/job_table.ts @@ -155,6 +155,14 @@ export function MachineLearningJobTableProvider( }); } + public async openAnnotationsTab(jobId: string) { + await retry.tryForTime(10000, async () => { + await this.ensureDetailsOpen(jobId); + await testSubjects.click(this.detailsSelector(jobId, 'mlJobListTab-annotations')); + await testSubjects.existOrFail('mlAnnotationsTable'); + }); + } + public async waitForRefreshButtonLoaded() { await testSubjects.existOrFail('~mlRefreshJobListButton', { timeout: 10 * 1000 }); await testSubjects.existOrFail('mlRefreshJobListButton loaded', { timeout: 30 * 1000 }); diff --git a/yarn.lock b/yarn.lock index 0199fabf82043..d8ee3ec9613f6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1227,10 +1227,10 @@ resolved "https://registry.yarnpkg.com/@bazel/ibazel/-/ibazel-0.15.10.tgz#cf0cff1aec6d8e7bb23e1fc618d09fbd39b7a13f" integrity sha512-0v+OwCQ6fsGFa50r6MXWbUkSGuWOoZ22K4pMSdtWiL5LKFIE4kfmMmtQS+M7/ICNwk2EIYob+NRreyi/DGUz5A== -"@bazel/typescript@^3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.6.0.tgz#4dda2e39505cde4a190f51118fbb82ea0e80fde6" - integrity sha512-cO58iHmSxM4mRHJLLbb3FfoJJxv0pMiVGFLORoiUy/EhLtyYGZ1e7ntf4GxEovwK/E4h/awjSUlQkzPThcukTg== +"@bazel/typescript@^3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.7.0.tgz#a4d648a36f7ef4960c8a16222f853a4c285a522d" + integrity sha512-bkNHZaCWg4Jk+10wzhFDhB+RRZkfob/yydC4qRzUVxCDLPFICYgC0PWeLhf/ixEhVeHtS0Cmv74M+QziqKSdbw== dependencies: protobufjs "6.8.8" semver "5.6.0"