From 1714b22de72bd63000649516b4c0cd4068ea00f3 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Mon, 25 Jan 2021 17:41:25 +0200 Subject: [PATCH 1/7] [Security Solution][Case] Improve cases and actions docs (#87817) --- x-pack/plugins/actions/README.md | 179 +++++++++++++++++++------------ x-pack/plugins/case/README.md | 40 ++++--- 2 files changed, 135 insertions(+), 84 deletions(-) diff --git a/x-pack/plugins/actions/README.md b/x-pack/plugins/actions/README.md index 12c3ab12a69986..9472cbf400a6a4 100644 --- a/x-pack/plugins/actions/README.md +++ b/x-pack/plugins/actions/README.md @@ -69,21 +69,26 @@ Table of Contents - [`secrets`](#secrets-6) - [`params`](#params-6) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice) - - [`subActionParams (getFields)`](#subactionparams-getfields-1) + - [`subActionParams (getFields)`](#subactionparams-getfields) - [Jira](#jira) - [`config`](#config-7) - [`secrets`](#secrets-7) - [`params`](#params-7) - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-1) + - [`subActionParams (getIncident)`](#subactionparams-getincident) - [`subActionParams (issueTypes)`](#subactionparams-issuetypes) - - [`subActionParams (getFields)`](#subactionparams-getfields-2) - - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-2) + - [`subActionParams (fieldsByIssueType)`](#subactionparams-fieldsbyissuetype) + - [`subActionParams (issues)`](#subactionparams-issues) + - [`subActionParams (issue)`](#subactionparams-issue) + - [`subActionParams (getFields)`](#subactionparams-getfields-1) - [IBM Resilient](#ibm-resilient) - [`config`](#config-8) - [`secrets`](#secrets-8) - [`params`](#params-8) - - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-3) - - [`subActionParams (getFields)`](#subactionparams-getfields-3) + - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-2) + - [`subActionParams (getFields)`](#subactionparams-getfields-2) + - [`subActionParams (incidentTypes)`](#subactionparams-incidenttypes) + - [`subActionParams (severity)`](#subactionparams-severity) - [Command Line Utility](#command-line-utility) - [Developing New Action Types](#developing-new-action-types) - [licensing](#licensing) @@ -526,17 +531,17 @@ The PagerDuty action uses the [V2 Events API](https://v2.developer.pagerduty.com ### `params` -| Property | Description | Type | -| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | -| eventAction | One of `trigger` _(default)_, `resolve`, or `acknowlege`. See [event action](https://v2.developer.pagerduty.com/docs/events-api-v2#event-action) for more details. | string _(optional)_ | -| dedupKey | All actions sharing this key will be associated with the same PagerDuty alert. Used to correlate trigger and resolution. The maximum length is **255** characters. See [alert deduplication](https://v2.developer.pagerduty.com/docs/events-api-v2#alert-de-duplication) for details. | string _(optional)_ | -| summary | A text summary of the event, defaults to `No summary provided`. The maximum length is **1024** characters. | string _(optional)_ | -| source | The affected system, preferably a hostname or fully qualified domain name. Defaults to `Kibana Action `. | string _(optional)_ | -| severity | The perceived severity of on the affected system. This can be one of `critical`, `error`, `warning` or `info`_(default)_. | string _(optional)_ | -| timestamp | An [ISO-8601 format date-time](https://v2.developer.pagerduty.com/v2/docs/types#datetime), indicating the time the event was detected or generated. | string _(optional)_ | -| component | The component of the source machine that is responsible for the event, for example `mysql` or `eth0`. | string _(optional)_ | -| group | Logical grouping of components of a service, for example `app-stack`. | string _(optional)_ | -| class | The class/type of the event, for example `ping failure` or `cpu load`. | string _(optional)_ | +| Property | Description | Type | +| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | +| eventAction | One of `trigger` _(default)_, `resolve`, or `acknowlege`. See [event action](https://v2.developer.pagerduty.com/docs/events-api-v2#event-action) for more details. | string _(optional)_ | +| dedupKey | All actions sharing this key will be associated with the same PagerDuty alert. Used to correlate trigger and resolution. The maximum length is **255** characters. See [alert deduplication](https://v2.developer.pagerduty.com/docs/events-api-v2#alert-de-duplication) for details. | string _(optional)_ | +| summary | A text summary of the event, defaults to `No summary provided`. The maximum length is **1024** characters. | string _(optional)_ | +| source | The affected system, preferably a hostname or fully qualified domain name. Defaults to `Kibana Action `. | string _(optional)_ | +| severity | The perceived severity of on the affected system. This can be one of `critical`, `error`, `warning` or `info`_(default)_. | string _(optional)_ | +| timestamp | An [ISO-8601 format date-time](https://v2.developer.pagerduty.com/v2/docs/types#datetime), indicating the time the event was detected or generated. | string _(optional)_ | +| component | The component of the source machine that is responsible for the event, for example `mysql` or `eth0`. | string _(optional)_ | +| group | Logical grouping of components of a service, for example `app-stack`. | string _(optional)_ | +| class | The class/type of the event, for example `ping failure` or `cpu load`. | string _(optional)_ | For more details see [PagerDuty v2 event parameters](https://v2.developer.pagerduty.com/v2/docs/send-an-event-events-api-v2). @@ -550,9 +555,9 @@ The ServiceNow action uses the [V2 Table API](https://developer.servicenow.com/a ### `config` -| Property | Description | Type | -| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------- | -| apiUrl | ServiceNow instance URL. | string | +| Property | Description | Type | +| -------- | ------------------------ | ------ | +| apiUrl | ServiceNow instance URL. | string | ### `secrets` @@ -563,24 +568,28 @@ The ServiceNow action uses the [V2 Table API](https://developer.servicenow.com/a ### `params` -| Property | Description | Type | -| --------------- | ------------------------------------------------------------------------------------ | ------ | -| subAction | The sub action to perform. It can be `getFields`, `pushToService`, `handshake`, and `getIncident` | string | -| subActionParams | The parameters of the sub action | object | +| Property | Description | Type | +| --------------- | --------------------------------------------------------------------- | ------ | +| subAction | The sub action to perform. It can be `getFields`, and `pushToService` | string | +| subActionParams | The parameters of the sub action | object | #### `subActionParams (pushToService)` -| Property | Description | Type | -| ------------- | ------------------------------------------------------------------------------------------------------------------------- | --------------------- | -| savedObjectId | The id of the saved object. | string | -| title | The title of the incident. | string _(optional)_ | -| description | The description of the incident. | string _(optional)_ | -| comment | A comment. | string _(optional)_ | -| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }`. | object[] _(optional)_ | -| externalId | The id of the incident in ServiceNow. If presented the incident will be update. Otherwise a new incident will be created. | string _(optional)_ | -| severity | The name of the severity in ServiceNow. | string _(optional)_ | -| urgency | The name of the urgency in ServiceNow. | string _(optional)_ | -| impact | The name of the impact in ServiceNow. | string _(optional)_ | +| Property | Description | Type | +| -------- | ------------------------------------------------------------------------------------------------------------- | --------------------- | +| incident | The ServiceNow incident. | object | +| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }`. | object[] _(optional)_ | + +The following table describes the properties of the `incident` object. + +| Property | Description | Type | +| ----------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------- | +| short_description | The title of the incident. | string | +| description | The description of the incident. | string _(optional)_ | +| externalId | The id of the incident in ServiceNow. If presented the incident will be update. Otherwise a new incident will be created. | string _(optional)_ | +| severity | The name of the severity in ServiceNow. | string _(optional)_ | +| urgency | The name of the urgency in ServiceNow. | string _(optional)_ | +| impact | The name of the impact in ServiceNow. | string _(optional)_ | #### `subActionParams (getFields)` @@ -596,9 +605,9 @@ The Jira action uses the [V2 API](https://developer.atlassian.com/cloud/jira/pla ### `config` -| Property | Description | Type | -| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | -| apiUrl | Jira instance URL. | string | +| Property | Description | Type | +| -------- | ------------------ | ------ | +| apiUrl | Jira instance URL. | string | ### `secrets` @@ -609,48 +618,71 @@ The Jira action uses the [V2 API](https://developer.atlassian.com/cloud/jira/pla ### `params` -| Property | Description | Type | -| --------------- | ----------------------------------------------------------------------------------------------------------------------- | ------ | -| subAction | The sub action to perform. It can be `getFields`, `pushToService`, `handshake`, `getIncident`, `issueTypes`, and `fieldsByIssueType` | string | -| subActionParams | The parameters of the sub action | object | +| Property | Description | Type | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------ | +| subAction | The sub action to perform. It can be `pushToService`, `getIncident`, `issueTypes`, `fieldsByIssueType`, `issues`, `issue`, and `getFields` | string | +| subActionParams | The parameters of the sub action | object | #### `subActionParams (pushToService)` -| Property | Description | Type | -| ------------- | ---------------------------------------------------------------------------------------------------------------- | --------------------- | -| savedObjectId | The id of the saved object | string | -| title | The title of the issue | string _(optional)_ | -| description | The description of the issue | string _(optional)_ | -| externalId | The id of the issue in Jira. If presented the incident will be update. Otherwise a new incident will be created. | string _(optional)_ | -| issueType | The id of the issue type in Jira. | string _(optional)_ | -| priority | The name of the priority in Jira. Example: `Medium`. | string _(optional)_ | -| labels | An array of labels. | string[] _(optional)_ | -| parent | The parent issue id or key. Only for `Sub-task` issue types. | string _(optional)_ | -| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }` | object[] _(optional)_ | +| Property | Description | Type | +| -------- | ------------------------------------------------------------------------------------------------------------- | --------------------- | +| incident | The Jira incident. | object | +| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }`. | object[] _(optional)_ | -#### `subActionParams (issueTypes)` +The following table describes the properties of the `incident` object. -No parameters for `issueTypes` sub-action. Provide an empty object `{}`. +| Property | Description | Type | +| ----------- | ---------------------------------------------------------------------------------------------------------------- | --------------------- | +| summary | The title of the issue | string | +| description | The description of the issue | string _(optional)_ | +| externalId | The id of the issue in Jira. If presented the incident will be update. Otherwise a new incident will be created. | string _(optional)_ | +| issueType | The id of the issue type in Jira. | string _(optional)_ | +| priority | The name of the priority in Jira. Example: `Medium`. | string _(optional)_ | +| labels | An array of labels. | string[] _(optional)_ | +| parent | The parent issue id or key. Only for `Sub-task` issue types. | string _(optional)_ | -#### `subActionParams (getFields)` +#### `subActionParams (getIncident)` -No parameters for `getFields` sub-action. Provide an empty object `{}`. +| Property | Description | Type | +| ---------- | --------------------------- | ------ | +| externalId | The id of the issue in Jira | string | -#### `subActionParams (pushToService)` +#### `subActionParams (issueTypes)` + +No parameters for `issueTypes` sub-action. Provide an empty object `{}`. + +#### `subActionParams (fieldsByIssueType)` | Property | Description | Type | | -------- | -------------------------------- | ------ | | id | The id of the issue type in Jira | string | +#### `subActionParams (issues)` + +| Property | Description | Type | +| -------- | ----------------------- | ------ | +| title | The title to search for | string | + +#### `subActionParams (issue)` + +| Property | Description | Type | +| -------- | --------------------------- | ------ | +| id | The id of the issue in Jira | string | + +#### `subActionParams (getFields)` + +No parameters for `getFields` sub-action. Provide an empty object `{}`. + ## IBM Resilient ID: `.resilient` ### `config` -| Property | Description | Type | -| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | -| apiUrl | IBM Resilient instance URL. | string | +| Property | Description | Type | +| -------- | --------------------------- | ------ | +| apiUrl | IBM Resilient instance URL. | string | ### `secrets` @@ -661,19 +693,24 @@ ID: `.resilient` ### `params` -| Property | Description | Type | -| --------------- | ------------------------------------------------------------------------------------ | ------ | -| subAction | The sub action to perform. It can be `getFields`, `pushToService`, `handshake`, and `getIncident` | string | -| subActionParams | The parameters of the sub action | object | +| Property | Description | Type | +| --------------- | -------------------------------------------------------------------------------------------------- | ------ | +| subAction | The sub action to perform. It can be `pushToService`, `getFields`, `incidentTypes`, and `severity` | string | +| subActionParams | The parameters of the sub action | object | #### `subActionParams (pushToService)` +| Property | Description | Type | +| -------- | ------------------------------------------------------------------------------------------------------------- | --------------------- | +| incident | The IBM Resilient incident. | object | +| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }`. | object[] _(optional)_ | + +The following table describes the properties of the `incident` object. + | Property | Description | Type | | ------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------- | -| savedObjectId | The id of the saved object | string | -| title | The title of the incident | string _(optional)_ | +| name | The title of the incident | string _(optional)_ | | description | The description of the incident | string _(optional)_ | -| comments | The comments of the incident. A comment is of the form `{ commentId: string, version: string, comment: string }` | object[] _(optional)_ | | externalId | The id of the incident in IBM Resilient. If presented the incident will be update. Otherwise a new incident will be created. | string _(optional)_ | | incidentTypes | An array with the ids of IBM Resilient incident types. | number[] _(optional)_ | | severityCode | IBM Resilient id of the severity code. | number _(optional)_ | @@ -682,6 +719,14 @@ ID: `.resilient` No parameters for `getFields` sub-action. Provide an empty object `{}`. +#### `subActionParams (incidentTypes)` + +No parameters for `incidentTypes` sub-action. Provide an empty object `{}`. + +#### `subActionParams (severity)` + +No parameters for `severity` sub-action. Provide an empty object `{}`. + # Command Line Utility The [`kbn-action`](https://github.com/pmuellr/kbn-action) tool can be used to send HTTP requests to the Actions plugin. For instance, to create a Slack action from the `.slack` Action Type, use the following command: diff --git a/x-pack/plugins/case/README.md b/x-pack/plugins/case/README.md index 30011148cd1e7b..069441ab640ee9 100644 --- a/x-pack/plugins/case/README.md +++ b/x-pack/plugins/case/README.md @@ -4,8 +4,7 @@ Elastic is developing a Case Management Workflow. Follow our progress: -- [Case API Documentation](https://documenter.getpostman.com/view/172706/SW7c2SuF?version=latest) -- [Github Meta](https://github.com/elastic/kibana/issues/50103) +- [Case API Documentation](https://www.elastic.co/guide/en/security/master/cases-overview.html) # Action types @@ -42,27 +41,28 @@ This action type has no `secrets` properties. | description | The case’s description. | string | | tags | String array containing words and phrases that help categorize cases. | string[] | | connector | Object containing the connector’s configuration. | [connector](#connector) | +| settings | Object containing the case’s settings. | [settings](#settings) | #### `subActionParams (update)` -| Property | Description | Type | -| ----------- | ---------------------------------------------------------- | ----------------------- | -| id | The ID of the case being updated. | string | -| tile | The updated case title. | string | -| description | The updated case description. | string | -| tags | The updated case tags. | string | -| connector | Object containing the connector’s configuration. | [connector](#connector) | -| status | The updated case status, which can be: `open` or `closed`. | string | -| version | The current case version. | string | +| Property | Description | Type | +| ----------- | ------------------------------------------------------------------------- | ----------------------- | +| id | The ID of the case being updated. | string | +| tile | The updated case title. | string | +| description | The updated case description. | string | +| tags | The updated case tags. | string | +| connector | Object containing the connector’s configuration. | [connector](#connector) | +| status | The updated case status, which can be: `open`, `in-progress` or `closed`. | string | +| settings | Object containing the case’s settings. | [settings](#settings) | +| version | The current case version. | string | #### `subActionParams (addComment)` -| Property | Description | Type | -| -------- | ----------------------------------------------------------------------- | ----------------- | -| type | The type of the comment | `user` \| `alert` | -| comment | The comment. Valid only when type is `user`. | string | -| alertId | The alert ID. Valid only when the type is `alert` | string | -| index | The index where the alert is saved. Valid only when the type is `alert` | string | +| Property | Description | Type | +| -------- | ------------------------ | ------ | +| type | The type of the comment. | `user` | +| comment | The comment. | string | + #### `connector` | Property | Description | Type | @@ -96,3 +96,9 @@ For IBM Resilient connectors: | ------------ | ------------------------------- | -------- | | issueTypes | The issue types of the issue. | string[] | | severityCode | The severity code of the issue. | string | + +#### `settings` + +| Property | Description | Type | +| ---------- | ------------------------------ | ------- | +| syncAlerts | Turn on or off alert synching. | boolean | \ No newline at end of file From 207c8eac5c50b45212b4c34e781fe2fef90fbc44 Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Mon, 25 Jan 2021 15:56:29 +0000 Subject: [PATCH 2/7] corrected terminology in PR template (#89095) We recently added a usage of `whitelist`, I've changed it to `allowlist` --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index efba93350b8fb7..2a5fc914662b63 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -11,7 +11,7 @@ Delete any items that are not applicable to this PR. - [ ] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) -- [ ] If a plugin configuration key changed, check if it needs to be whitelisted in the [cloud](https://github.com/elastic/cloud) and added to the [docker list](https://github.com/elastic/kibana/blob/c29adfef29e921cc447d2a5ed06ac2047ceab552/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker) +- [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the [cloud](https://github.com/elastic/cloud) and added to the [docker list](https://github.com/elastic/kibana/blob/c29adfef29e921cc447d2a5ed06ac2047ceab552/src/dev/build/tasks/os_packages/docker_generator/resources/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) From f6837a1f66db9909768afdd68bf2f0be8c3087f4 Mon Sep 17 00:00:00 2001 From: Gidi Meir Morris Date: Mon, 25 Jan 2021 15:57:50 +0000 Subject: [PATCH 3/7] made unit test more reliable (#89094) Made unit test more reliable by using resolving promises rather than timed `await`s that could be flaky when the node event loop is overwhelmed. --- .../task_manager/server/task_pool.test.ts | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/x-pack/plugins/task_manager/server/task_pool.test.ts b/x-pack/plugins/task_manager/server/task_pool.test.ts index 324e376c32d95a..14ad0561928f85 100644 --- a/x-pack/plugins/task_manager/server/task_pool.test.ts +++ b/x-pack/plugins/task_manager/server/task_pool.test.ts @@ -13,6 +13,7 @@ import { Logger } from '../../../../src/core/server'; import { asOk } from './lib/result_type'; import { SavedObjectsErrorHelpers } from '../../../../src/core/server'; import moment from 'moment'; +import uuid from 'uuid'; describe('TaskPool', () => { test('occupiedWorkers are a sum of running tasks', async () => { @@ -133,7 +134,7 @@ describe('TaskPool', () => { const result = await pool.run([mockTask(), taskFailedToRun, mockTask()]); expect(logger.debug).toHaveBeenCalledWith( - 'Task TaskType "shooooo" failed in attempt to run: Saved object [task/foo] not found' + `Task TaskType "shooooo" failed in attempt to run: Saved object [task/${taskFailedToRun.id}] not found` ); expect(logger.warn).not.toHaveBeenCalled(); @@ -203,26 +204,28 @@ describe('TaskPool', () => { sinon.assert.calledOnce(secondRun); }); - test.skip('run cancels expired tasks prior to running new tasks', async () => { + test('run cancels expired tasks prior to running new tasks', async () => { const logger = loggingSystemMock.create().get(); const pool = new TaskPool({ maxWorkers$: of(2), logger, }); - const readyToExpire = resolvable(); + const haltUntilWeAfterFirstRun = resolvable(); const taskHasExpired = resolvable(); + const haltTaskSoThatItCanBeCanceled = resolvable(); + const shouldRun = sinon.spy(() => Promise.resolve()); const shouldNotRun = sinon.spy(() => Promise.resolve()); const now = new Date(); const result = await pool.run([ { - ...mockTask(), + ...mockTask({ id: '1' }), async run() { - await readyToExpire; + await haltUntilWeAfterFirstRun; this.isExpired = true; taskHasExpired.resolve(); - await sleep(10); + await haltTaskSoThatItCanBeCanceled; return asOk({ state: {} }); }, get expiration() { @@ -235,9 +238,10 @@ describe('TaskPool', () => { cancel: shouldRun, }, { - ...mockTask(), + ...mockTask({ id: '2' }), async run() { - await sleep(10); + // halt here so that we can verify that this task is counted in `occupiedWorkers` + await haltUntilWeAfterFirstRun; return asOk({ state: {} }); }, cancel: shouldNotRun, @@ -248,16 +252,19 @@ describe('TaskPool', () => { expect(pool.occupiedWorkers).toEqual(2); expect(pool.availableWorkers).toEqual(0); - readyToExpire.resolve(); + // release first stage in task so that it has time to expire, but not complete + haltUntilWeAfterFirstRun.resolve(); await taskHasExpired; - expect(await pool.run([{ ...mockTask() }])).toBeTruthy(); + expect(await pool.run([{ ...mockTask({ id: '3' }) }])).toBeTruthy(); sinon.assert.calledOnce(shouldRun); sinon.assert.notCalled(shouldNotRun); - expect(pool.occupiedWorkers).toEqual(2); - expect(pool.availableWorkers).toEqual(0); + expect(pool.occupiedWorkers).toEqual(1); + expect(pool.availableWorkers).toEqual(1); + + haltTaskSoThatItCanBeCanceled.resolve(); expect(logger.warn).toHaveBeenCalledWith( `Cancelling task TaskType "shooooo" as it expired at ${now.toISOString()} after running for 05m 30s (with timeout set at 5m).` @@ -355,10 +362,10 @@ describe('TaskPool', () => { }); } - function mockTask() { + function mockTask(overrides = {}) { return { isExpired: false, - id: 'foo', + id: uuid.v4(), cancel: async () => undefined, markTaskAsRunning: jest.fn(async () => true), run: mockRun(), @@ -377,6 +384,7 @@ describe('TaskPool', () => { createTaskRunner: jest.fn(), }; }, + ...overrides, }; } }); From e251ff4be593d45d6094efb414b1dccecff42072 Mon Sep 17 00:00:00 2001 From: Oliver Gupte Date: Mon, 25 Jan 2021 08:05:32 -0800 Subject: [PATCH 4/7] [APM] Renames significant terms feature to "Correlations" (#88974) (#89028) * [APM] Renames significant terms feature to "Correlations" (#88974) * fix capitalizations Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/apm/common/ui_settings_keys.ts | 2 +- .../app/Correlations/LatencyCorrelations.tsx | 2 +- .../apm/public/components/app/Correlations/index.tsx | 10 +++++----- x-pack/plugins/apm/server/ui_settings.ts | 9 ++++----- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/apm/common/ui_settings_keys.ts b/x-pack/plugins/apm/common/ui_settings_keys.ts index ffc2a2ef21fe90..38922fa445a471 100644 --- a/x-pack/plugins/apm/common/ui_settings_keys.ts +++ b/x-pack/plugins/apm/common/ui_settings_keys.ts @@ -4,5 +4,5 @@ * you may not use this file except in compliance with the Elastic License. */ -export const enableSignificantTerms = 'apm:enableSignificantTerms'; +export const enableCorrelations = 'apm:enableCorrelations'; export const enableServiceOverview = 'apm:enableServiceOverview'; diff --git a/x-pack/plugins/apm/public/components/app/Correlations/LatencyCorrelations.tsx b/x-pack/plugins/apm/public/components/app/Correlations/LatencyCorrelations.tsx index b2d88c4c3849b9..438303110fbc46 100644 --- a/x-pack/plugins/apm/public/components/app/Correlations/LatencyCorrelations.tsx +++ b/x-pack/plugins/apm/public/components/app/Correlations/LatencyCorrelations.tsx @@ -128,7 +128,7 @@ export function LatencyCorrelations() { - View significant terms + View correlations @@ -62,7 +62,7 @@ export function Correlations() { > -

Significant terms

+

Correlations

@@ -88,7 +88,7 @@ export function Correlations() { iconType="alert" >

- Significant terms is an experimental feature and in active + Correlations is an experimental feature and in active development. Bugs and surprises are to be expected but let us know your feedback so we can improve it.

diff --git a/x-pack/plugins/apm/server/ui_settings.ts b/x-pack/plugins/apm/server/ui_settings.ts index c86fb636b5a1a6..e9bb747280fc7c 100644 --- a/x-pack/plugins/apm/server/ui_settings.ts +++ b/x-pack/plugins/apm/server/ui_settings.ts @@ -8,7 +8,7 @@ import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; import { UiSettingsParams } from '../../../../src/core/types'; import { - enableSignificantTerms, + enableCorrelations, enableServiceOverview, } from '../common/ui_settings_keys'; @@ -16,17 +16,16 @@ import { * uiSettings definitions for APM. */ export const uiSettings: Record> = { - [enableSignificantTerms]: { + [enableCorrelations]: { category: ['observability'], name: i18n.translate('xpack.apm.enableCorrelationsExperimentName', { - defaultMessage: 'APM Significant terms (Platinum required)', + defaultMessage: 'APM correlations (Platinum required)', }), value: false, description: i18n.translate( 'xpack.apm.enableCorrelationsExperimentDescription', { - defaultMessage: - 'Enable the experimental Significant terms feature in APM', + defaultMessage: 'Enable the experimental correlations feature in APM', } ), schema: schema.boolean(), From 6391ef9c45409cdd47d13f5b5fb420d092562b68 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 25 Jan 2021 17:08:31 +0100 Subject: [PATCH 5/7] [Observability] Lazy load shared components (#88802) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../app/RumDashboard/UXMetrics/index.tsx | 23 ++++++++++------ .../public/components/app/header/index.tsx | 2 +- .../components/app/section/ux/index.tsx | 2 +- .../shared/core_web_vitals/index.tsx | 17 ++++-------- .../components/shared/header_menu_portal.tsx | 12 +++------ .../public/components/shared/index.tsx | 26 +++++++++++++++++++ .../public/components/shared/types.ts | 23 ++++++++++++++++ x-pack/plugins/observability/public/index.ts | 6 ++--- 8 files changed, 78 insertions(+), 33 deletions(-) create mode 100644 x-pack/plugins/observability/public/components/shared/index.tsx create mode 100644 x-pack/plugins/observability/public/components/shared/types.ts diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/index.tsx index 392b42cba12e57..29d5750231762c 100644 --- a/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/RumDashboard/UXMetrics/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useContext } from 'react'; +import React, { useContext, useMemo } from 'react'; import { EuiFlexGroup, EuiFlexItem, @@ -17,7 +17,7 @@ import { I18LABELS } from '../translations'; import { KeyUXMetrics } from './KeyUXMetrics'; import { useFetcher } from '../../../../hooks/use_fetcher'; import { useUxQuery } from '../hooks/useUxQuery'; -import { CoreVitals } from '../../../../../../observability/public'; +import { getCoreVitalsComponent } from '../../../../../../observability/public'; import { CsmSharedContext } from '../CsmSharedContext'; import { useUrlParams } from '../../../../context/url_params_context/use_url_params'; import { getPercentileLabel } from './translations'; @@ -48,6 +48,18 @@ export function UXMetrics() { sharedData: { totalPageViews }, } = useContext(CsmSharedContext); + const CoreVitals = useMemo( + () => + getCoreVitalsComponent({ + data, + totalPageViews, + loading: status !== 'success', + displayTrafficMetric: true, + }), + // eslint-disable-next-line react-hooks/exhaustive-deps + [status] + ); + return ( @@ -67,12 +79,7 @@ export function UXMetrics() { - + {CoreVitals} diff --git a/x-pack/plugins/observability/public/components/app/header/index.tsx b/x-pack/plugins/observability/public/components/app/header/index.tsx index b195bb52e7ed29..097871fe020e53 100644 --- a/x-pack/plugins/observability/public/components/app/header/index.tsx +++ b/x-pack/plugins/observability/public/components/app/header/index.tsx @@ -17,7 +17,7 @@ import { i18n } from '@kbn/i18n'; import React, { ReactNode } from 'react'; import styled from 'styled-components'; import { usePluginContext } from '../../../hooks/use_plugin_context'; -import { HeaderMenuPortal } from '../../shared/header_menu_portal'; +import HeaderMenuPortal from '../../shared/header_menu_portal'; const Container = styled.div<{ color: string }>` background: ${(props) => props.color}; diff --git a/x-pack/plugins/observability/public/components/app/section/ux/index.tsx b/x-pack/plugins/observability/public/components/app/section/ux/index.tsx index 43f1072d06fc2d..7074a895d058b7 100644 --- a/x-pack/plugins/observability/public/components/app/section/ux/index.tsx +++ b/x-pack/plugins/observability/public/components/app/section/ux/index.tsx @@ -12,7 +12,7 @@ import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; import { useHasData } from '../../../../hooks/use_has_data'; import { useTimeRange } from '../../../../hooks/use_time_range'; import { UXHasDataResponse } from '../../../../typings'; -import { CoreVitals } from '../../../shared/core_web_vitals'; +import CoreVitals from '../../../shared/core_web_vitals'; interface Props { bucketSize: string; diff --git a/x-pack/plugins/observability/public/components/shared/core_web_vitals/index.tsx b/x-pack/plugins/observability/public/components/shared/core_web_vitals/index.tsx index f573c8cfc1f97a..7d40ce089cec4d 100644 --- a/x-pack/plugins/observability/public/components/shared/core_web_vitals/index.tsx +++ b/x-pack/plugins/observability/public/components/shared/core_web_vitals/index.tsx @@ -16,6 +16,7 @@ import { import { CoreVitalItem } from './core_vital_item'; import { WebCoreVitalsTitle } from './web_core_vitals_title'; import { ServiceName } from './service_name'; +import { CoreVitalProps } from '../types'; export interface UXMetrics { cls: number | null; @@ -29,7 +30,7 @@ export interface UXMetrics { clsRanks: number[]; } -export function formatToSec(value?: number | string, fromUnit = 'MicroSec'): string { +function formatToSec(value?: number | string, fromUnit = 'MicroSec'): string { const valueInMs = Number(value ?? 0) / (fromUnit === 'MicroSec' ? 1000 : 1); if (valueInMs < 1000) { @@ -51,23 +52,15 @@ const CoreVitalsThresholds = { CLS: { good: '0.1', bad: '0.25' }, }; -interface Props { - loading: boolean; - data?: UXMetrics | null; - displayServiceName?: boolean; - serviceName?: string; - totalPageViews?: number; - displayTrafficMetric?: boolean; -} - -export function CoreVitals({ +// eslint-disable-next-line import/no-default-export +export default function CoreVitals({ data, loading, displayServiceName, serviceName, totalPageViews, displayTrafficMetric = false, -}: Props) { +}: CoreVitalProps) { const { lcp, lcpRanks, fid, fidRanks, cls, clsRanks, coreVitalPages } = data || {}; return ( diff --git a/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx b/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx index ca03eb6ddb45aa..e209e830d0f37a 100644 --- a/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx +++ b/x-pack/plugins/observability/public/components/shared/header_menu_portal.tsx @@ -4,17 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { ReactNode, useEffect, useMemo } from 'react'; +import React, { useEffect, useMemo } from 'react'; import { createPortalNode, InPortal, OutPortal } from 'react-reverse-portal'; -import { AppMountParameters } from '../../../../../../src/core/public'; import { toMountPoint } from '../../../../../../src/plugins/kibana_react/public'; +import { HeaderMenuPortalProps } from './types'; -interface HeaderMenuPortalProps { - children: ReactNode; - setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; -} - -export function HeaderMenuPortal({ children, setHeaderActionMenu }: HeaderMenuPortalProps) { +// eslint-disable-next-line import/no-default-export +export default function HeaderMenuPortal({ children, setHeaderActionMenu }: HeaderMenuPortalProps) { const portalNode = useMemo(() => createPortalNode(), []); useEffect(() => { diff --git a/x-pack/plugins/observability/public/components/shared/index.tsx b/x-pack/plugins/observability/public/components/shared/index.tsx new file mode 100644 index 00000000000000..6e3835129beb2f --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/index.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { lazy, Suspense } from 'react'; +import { CoreVitalProps, HeaderMenuPortalProps } from './types'; + +export function getCoreVitalsComponent(props: CoreVitalProps) { + const CoreVitalsLazy = lazy(() => import('./core_web_vitals/index')); + return ( + + + + ); +} + +export function HeaderMenuPortal(props: HeaderMenuPortalProps) { + const HeaderMenuPortalLazy = lazy(() => import('./header_menu_portal')); + return ( + + + + ); +} diff --git a/x-pack/plugins/observability/public/components/shared/types.ts b/x-pack/plugins/observability/public/components/shared/types.ts new file mode 100644 index 00000000000000..9039f444f550f1 --- /dev/null +++ b/x-pack/plugins/observability/public/components/shared/types.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ReactNode } from 'react'; +import { AppMountParameters } from '../../../../../../src/core/public'; +import { UXMetrics } from './core_web_vitals'; + +export interface HeaderMenuPortalProps { + children: ReactNode; + setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; +} + +export interface CoreVitalProps { + loading: boolean; + data?: UXMetrics | null; + displayServiceName?: boolean; + serviceName?: string; + totalPageViews?: number; + displayTrafficMetric?: boolean; +} diff --git a/x-pack/plugins/observability/public/index.ts b/x-pack/plugins/observability/public/index.ts index 22cc5faf239675..c052541956c139 100644 --- a/x-pack/plugins/observability/public/index.ts +++ b/x-pack/plugins/observability/public/index.ts @@ -6,8 +6,7 @@ import { PluginInitializerContext, PluginInitializer } from 'kibana/public'; import { Plugin, ObservabilityPluginSetup, ObservabilityPluginStart } from './plugin'; -export { HeaderMenuPortal } from './components/shared/header_menu_portal'; -export { ObservabilityPluginSetup, ObservabilityPluginStart }; +export type { ObservabilityPluginSetup, ObservabilityPluginStart }; export const plugin: PluginInitializer = ( context: PluginInitializerContext @@ -17,7 +16,8 @@ export const plugin: PluginInitializer Date: Mon, 25 Jan 2021 16:20:14 +0000 Subject: [PATCH 6/7] [ML] Add ML deep links to navigational search (#88958) * [ML] Add ML deep links to navigational search * [ML] Refactor register helper files * [ML] Edit import in search_deep_links * [ML] Move register_feature out of register_helper * [ML] Add comment about registerFeature Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/ml/public/plugin.ts | 37 +++--- .../ml/public/register_helper/index.ts | 10 ++ .../register_search_links/index.ts} | 5 +- .../register_search_links.ts | 27 +++++ .../search_deep_links.ts | 110 ++++++++++++++++++ 5 files changed, 172 insertions(+), 17 deletions(-) create mode 100644 x-pack/plugins/ml/public/register_helper/index.ts rename x-pack/plugins/ml/public/{register_helper.ts => register_helper/register_search_links/index.ts} (51%) create mode 100644 x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts create mode 100644 x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts diff --git a/x-pack/plugins/ml/public/plugin.ts b/x-pack/plugins/ml/public/plugin.ts index 1cc69ac2239ab7..7c32671be93c44 100644 --- a/x-pack/plugins/ml/public/plugin.ts +++ b/x-pack/plugins/ml/public/plugin.ts @@ -70,7 +70,7 @@ export interface MlSetupDependencies { export type MlCoreSetup = CoreSetup; export class MlPlugin implements Plugin { - private appUpdater = new BehaviorSubject(() => ({})); + private appUpdater$ = new BehaviorSubject(() => ({})); private urlGenerator: undefined | UrlGeneratorContract; constructor(private initializerContext: PluginInitializerContext) {} @@ -85,7 +85,7 @@ export class MlPlugin implements Plugin { euiIconType: PLUGIN_ICON_SOLUTION, appRoute: '/app/ml', category: DEFAULT_APP_CATEGORIES.kibana, - updater$: this.appUpdater, + updater$: this.appUpdater$, mount: async (params: AppMountParameters) => { const [coreStart, pluginsStart] = await core.getStartServices(); const kibanaVersion = this.initializerContext.env.packageInfo.version; @@ -133,23 +133,34 @@ export class MlPlugin implements Plugin { }); } else { // if ml is disabled in elasticsearch, disable ML in kibana - this.appUpdater.next(() => ({ + this.appUpdater$.next(() => ({ status: AppStatus.inaccessible, })); } // register various ML plugin features which require a full license - const { registerEmbeddables, registerManagementSection, registerMlUiActions } = await import( - './register_helper' - ); - - if (isMlEnabled(license) && isFullLicense(license)) { - const canManageMLJobs = capabilities.management?.insightsAndAlerting?.jobsListLink ?? false; - if (canManageMLJobs && pluginsSetup.management !== undefined) { - registerManagementSection(pluginsSetup.management, core).enable(); + // note including registerFeature in register_helper would cause the page bundle size to increase significantly + const { + registerEmbeddables, + registerManagementSection, + registerMlUiActions, + registerSearchLinks, + } = await import('./register_helper'); + + const mlEnabled = isMlEnabled(license); + const fullLicense = isFullLicense(license); + if (mlEnabled) { + registerSearchLinks(this.appUpdater$, fullLicense); + + if (fullLicense) { + const canManageMLJobs = + capabilities.management?.insightsAndAlerting?.jobsListLink ?? false; + if (canManageMLJobs && pluginsSetup.management !== undefined) { + registerManagementSection(pluginsSetup.management, core).enable(); + } + registerEmbeddables(pluginsSetup.embeddable, core); + registerMlUiActions(pluginsSetup.uiActions, core); } - registerEmbeddables(pluginsSetup.embeddable, core); - registerMlUiActions(pluginsSetup.uiActions, core); } }); diff --git a/x-pack/plugins/ml/public/register_helper/index.ts b/x-pack/plugins/ml/public/register_helper/index.ts new file mode 100644 index 00000000000000..8e62b6562520a6 --- /dev/null +++ b/x-pack/plugins/ml/public/register_helper/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { registerEmbeddables } from '../embeddables'; +export { registerManagementSection } from '../application/management'; +export { registerMlUiActions } from '../ui_actions'; +export { registerSearchLinks } from './register_search_links'; diff --git a/x-pack/plugins/ml/public/register_helper.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/index.ts similarity index 51% rename from x-pack/plugins/ml/public/register_helper.ts rename to x-pack/plugins/ml/public/register_helper/register_search_links/index.ts index 50ec53a10ece9b..e1912c7ebabeba 100644 --- a/x-pack/plugins/ml/public/register_helper.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/index.ts @@ -4,7 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { registerEmbeddables } from './embeddables'; -export { registerFeature } from './register_feature'; -export { registerManagementSection } from './application/management'; -export { registerMlUiActions } from './ui_actions'; +export { registerSearchLinks } from './register_search_links'; diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts new file mode 100644 index 00000000000000..2df7e8140698a8 --- /dev/null +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { BehaviorSubject } from 'rxjs'; + +import { AppUpdater } from 'src/core/public'; +import { getSearchDeepLinks } from './search_deep_links'; + +export function registerSearchLinks( + appUpdater: BehaviorSubject, + isFullLicense: boolean +) { + appUpdater.next(() => ({ + meta: { + keywords: [ + i18n.translate('xpack.ml.keyword.ml', { + defaultMessage: 'ML', + }), + ], + searchDeepLinks: getSearchDeepLinks(isFullLicense), + }, + })); +} diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts new file mode 100644 index 00000000000000..7108fb7af56705 --- /dev/null +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; + +import type { AppSearchDeepLink } from 'src/core/public'; +import { ML_PAGES } from '../../../common/constants/ml_url_generator'; + +const OVERVIEW_LINK_SEARCH_DEEP_LINK: AppSearchDeepLink = { + id: 'mlOverviewSearchDeepLink', + title: i18n.translate('xpack.ml.searchDeepLink.overview', { + defaultMessage: 'Overview', + }), + path: `/${ML_PAGES.OVERVIEW}`, +}; + +const ANOMALY_DETECTION_SEARCH_DEEP_LINK: AppSearchDeepLink = { + id: 'mlAnomalyDetectionSearchDeepLink', + title: i18n.translate('xpack.ml.searchDeepLink.anomalyDetection', { + defaultMessage: 'Anomaly Detection', + }), + path: `/${ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE}`, +}; + +const DATA_FRAME_ANALYTICS_SEARCH_DEEP_LINK: AppSearchDeepLink = { + id: 'mlDataFrameAnalyticsSearchDeepLink', + title: i18n.translate('xpack.ml.searchDeepLink.dataFrameAnalytics', { + defaultMessage: 'Data Frame Analytics', + }), + path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_JOBS_MANAGE}`, + searchDeepLinks: [ + { + id: 'mlTrainedModelsSearchDeepLink', + title: i18n.translate('xpack.ml.searchDeepLink.trainedModels', { + defaultMessage: 'Trained Models', + }), + path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_MODELS_MANAGE}`, + }, + ], +}; + +const DATA_VISUALIZER_SEARCH_DEEP_LINK: AppSearchDeepLink = { + id: 'mlDataVisualizerSearchDeepLink', + title: i18n.translate('xpack.ml.searchDeepLink.dataVisualizer', { + defaultMessage: 'Data Visualizer', + }), + path: `/${ML_PAGES.DATA_VISUALIZER}`, +}; + +const FILE_UPLOAD_SEARCH_DEEP_LINK: AppSearchDeepLink = { + id: 'mlFileUploadSearchDeepLink', + title: i18n.translate('xpack.ml.searchDeepLink.fileUpload', { + defaultMessage: 'File Upload', + }), + path: `/${ML_PAGES.DATA_VISUALIZER_FILE}`, +}; + +const INDEX_DATA_VISUALIZER_SEARCH_DEEP_LINK: AppSearchDeepLink = { + id: 'mlIndexDataVisualizerSearchDeepLink', + title: i18n.translate('xpack.ml.searchDeepLink.indexDataVisualizer', { + defaultMessage: 'Index Data Visualizer', + }), + path: `/${ML_PAGES.DATA_VISUALIZER_INDEX_SELECT}`, +}; + +const SETTINGS_SEARCH_DEEP_LINK: AppSearchDeepLink = { + id: 'mlSettingsSearchDeepLink', + title: i18n.translate('xpack.ml.searchDeepLink.settings', { + defaultMessage: 'Settings', + }), + path: `/${ML_PAGES.SETTINGS}`, + searchDeepLinks: [ + { + id: 'mlCalendarSettingsSearchDeepLink', + title: i18n.translate('xpack.ml.searchDeepLink.calendarSettings', { + defaultMessage: 'Calendars', + }), + path: `/${ML_PAGES.CALENDARS_MANAGE}`, + }, + { + id: 'mlFilterListsSettingsSearchDeepLink', + title: i18n.translate('xpack.ml.searchDeepLink.filterListsSettings', { + defaultMessage: 'Filter Lists', + }), + path: `/${ML_PAGES.SETTINGS}`, // Link to settings page as read only users cannot view filter lists. + }, + ], +}; + +export function getSearchDeepLinks(isFullLicense: boolean) { + const deepLinks: AppSearchDeepLink[] = [ + DATA_VISUALIZER_SEARCH_DEEP_LINK, + FILE_UPLOAD_SEARCH_DEEP_LINK, + INDEX_DATA_VISUALIZER_SEARCH_DEEP_LINK, + ]; + + if (isFullLicense === true) { + deepLinks.push( + OVERVIEW_LINK_SEARCH_DEEP_LINK, + ANOMALY_DETECTION_SEARCH_DEEP_LINK, + DATA_FRAME_ANALYTICS_SEARCH_DEEP_LINK, + SETTINGS_SEARCH_DEEP_LINK + ); + } + + return deepLinks; +} From 43db7e365ff53e9014934910c34ee647eac29955 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Mon, 25 Jan 2021 11:27:59 -0500 Subject: [PATCH 7/7] [Search Profiler] Migrate server to new es-js client (#88725) --- .../searchprofiler/server/routes/profile.ts | 20 +++---- x-pack/test/api_integration/apis/index.ts | 1 + .../apis/searchprofiler/index.ts | 13 +++++ .../apis/searchprofiler/searchprofiler.ts | 56 +++++++++++++++++++ 4 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 x-pack/test/api_integration/apis/searchprofiler/index.ts create mode 100644 x-pack/test/api_integration/apis/searchprofiler/searchprofiler.ts diff --git a/x-pack/plugins/searchprofiler/server/routes/profile.ts b/x-pack/plugins/searchprofiler/server/routes/profile.ts index 914c688a080f86..87f2ec1df1c922 100644 --- a/x-pack/plugins/searchprofiler/server/routes/profile.ts +++ b/x-pack/plugins/searchprofiler/server/routes/profile.ts @@ -27,10 +27,6 @@ export const register = ({ router, getLicenseStatus, log }: RouteDependencies) = }); } - const { - core: { elasticsearch }, - } = ctx; - const { body: { query, index }, } = request; @@ -46,21 +42,25 @@ export const register = ({ router, getLicenseStatus, log }: RouteDependencies) = body: JSON.stringify(parsed, null, 2), }; try { - const resp = await elasticsearch.legacy.client.callAsCurrentUser('search', body); + const client = ctx.core.elasticsearch.client.asCurrentUser; + const resp = await client.search(body); + return response.ok({ body: { ok: true, - resp, + resp: resp.body, }, }); } catch (err) { log.error(err); + const { statusCode, body: errorBody } = err; + return response.customError({ - statusCode: err.status || 500, - body: err.body + statusCode: statusCode || 500, + body: errorBody ? { - message: err.message, - attributes: err.body, + message: errorBody.error?.reason, + attributes: errorBody, } : err, }); diff --git a/x-pack/test/api_integration/apis/index.ts b/x-pack/test/api_integration/apis/index.ts index 6b6326df017aaa..2cd2654cffe3ee 100644 --- a/x-pack/test/api_integration/apis/index.ts +++ b/x-pack/test/api_integration/apis/index.ts @@ -33,5 +33,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./transform')); loadTestFile(require.resolve('./lists')); loadTestFile(require.resolve('./upgrade_assistant')); + loadTestFile(require.resolve('./searchprofiler')); }); } diff --git a/x-pack/test/api_integration/apis/searchprofiler/index.ts b/x-pack/test/api_integration/apis/searchprofiler/index.ts new file mode 100644 index 00000000000000..36794feb00d1be --- /dev/null +++ b/x-pack/test/api_integration/apis/searchprofiler/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Search Profiler', () => { + loadTestFile(require.resolve('./searchprofiler')); + }); +} diff --git a/x-pack/test/api_integration/apis/searchprofiler/searchprofiler.ts b/x-pack/test/api_integration/apis/searchprofiler/searchprofiler.ts new file mode 100644 index 00000000000000..041cfb82520b4b --- /dev/null +++ b/x-pack/test/api_integration/apis/searchprofiler/searchprofiler.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +const API_BASE_PATH = '/api/searchprofiler'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('Profile', () => { + it('should return profile results for a valid index', async () => { + const payload = { + index: '_all', + query: { + query: { + match_all: {}, + }, + }, + }; + + const { body } = await supertest + .post(`${API_BASE_PATH}/profile`) + .set('kbn-xsrf', 'xxx') + .set('Content-Type', 'application/json;charset=UTF-8') + .send(payload) + .expect(200); + + expect(body.ok).to.eql(true); + }); + + it('should return error for invalid index', async () => { + const payloadWithInvalidIndex = { + index: 'index_does_not_exist', + query: { + query: { + match_all: {}, + }, + }, + }; + + const { body } = await supertest + .post(`${API_BASE_PATH}/execute`) + .set('kbn-xsrf', 'xxx') + .set('Content-Type', 'application/json;charset=UTF-8') + .send(payloadWithInvalidIndex) + .expect(404); + + expect(body.error).to.eql('Not Found'); + }); + }); +}