diff --git a/x-pack/build_chromium/README.md b/x-pack/build_chromium/README.md index 7c81e46318a1ce..9934d06a9d96a5 100644 --- a/x-pack/build_chromium/README.md +++ b/x-pack/build_chromium/README.md @@ -20,6 +20,7 @@ gain familiarity. ## Usage ``` +export PATH=$HOME/chromium/depot_tools:$PATH # Create a dedicated working directory for this directory of Python scripts. mkdir ~/chromium && cd ~/chromium # Copy the scripts from the Kibana repo to use them conveniently in the working directory diff --git a/x-pack/plugins/apm/server/lib/services/get_throughput.ts b/x-pack/plugins/apm/server/lib/services/get_throughput.ts index 29071f96e3a06f..bde826a568da95 100644 --- a/x-pack/plugins/apm/server/lib/services/get_throughput.ts +++ b/x-pack/plugins/apm/server/lib/services/get_throughput.ts @@ -27,12 +27,17 @@ interface Options { type ESResponse = PromiseReturnType; -function transform(response: ESResponse) { +function transform(response: ESResponse, options: Options) { + const { end, start } = options.setup; + const deltaAsMinutes = (end - start) / 1000 / 60; if (response.hits.total.value === 0) { return []; } const buckets = response.aggregations?.throughput.buckets ?? []; - return buckets.map(({ key: x, doc_count: y }) => ({ x, y })); + return buckets.map(({ key: x, doc_count: y }) => ({ + x, + y: y / deltaAsMinutes, + })); } async function fetcher({ @@ -82,6 +87,6 @@ async function fetcher({ export async function getThroughput(options: Options) { return { - throughput: transform(await fetcher(options)), + throughput: transform(await fetcher(options), options), }; } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 1e81795eb23289..ca58c43ba3f98b 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -21446,9 +21446,6 @@ "xpack.triggersActionsUI.components.healthCheck.encryptionErrorAfterKey": " kibana.ymlファイルで", "xpack.triggersActionsUI.components.healthCheck.encryptionErrorBeforeKey": "アラートを作成するには、値を設定します ", "xpack.triggersActionsUI.components.healthCheck.encryptionErrorTitle": "暗号化鍵を設定する必要があります", - "xpack.triggersActionsUI.components.healthCheck.tlsAndEncryptionError": "KibanaとElasticsearchの間でトランスポートレイヤーセキュリティを有効にし、kibana.ymlファイルで暗号化鍵を構成する必要があります。", - "xpack.triggersActionsUI.components.healthCheck.tlsAndEncryptionErrorAction": "方法を学習", - "xpack.triggersActionsUI.components.healthCheck.tlsAndEncryptionErrorTitle": "追加の設定が必要です", "xpack.triggersActionsUI.components.healthCheck.tlsError": "アラートはAPIキーに依存し、キーを使用するにはElasticsearchとKibanaの間にTLSが必要です。", "xpack.triggersActionsUI.components.healthCheck.tlsErrorAction": "TLSを有効にする方法をご覧ください。", "xpack.triggersActionsUI.components.healthCheck.tlsErrorTitle": "トランスポートレイヤーセキュリティを有効にする必要があります", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 4d21a05cab09a5..ae148b9a0c133a 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -21496,9 +21496,6 @@ "xpack.triggersActionsUI.components.healthCheck.encryptionErrorAfterKey": " 。", "xpack.triggersActionsUI.components.healthCheck.encryptionErrorBeforeKey": "要创建告警,请在 kibana.yml 文件中设置以下项的值: ", "xpack.triggersActionsUI.components.healthCheck.encryptionErrorTitle": "必须设置加密密钥", - "xpack.triggersActionsUI.components.healthCheck.tlsAndEncryptionError": "必须在 Kibana 和 Elasticsearch 之间启用传输层安全并在 kibana.yml 文件中配置加密密钥。", - "xpack.triggersActionsUI.components.healthCheck.tlsAndEncryptionErrorAction": "了解操作方法", - "xpack.triggersActionsUI.components.healthCheck.tlsAndEncryptionErrorTitle": "需要其他设置", "xpack.triggersActionsUI.components.healthCheck.tlsError": "Alerting 功能依赖于 API 密钥,这需要在 Elasticsearch 与 Kibana 之间启用 TLS。", "xpack.triggersActionsUI.components.healthCheck.tlsErrorAction": "了解如何启用 TLS。", "xpack.triggersActionsUI.components.healthCheck.tlsErrorTitle": "必须启用传输层安全", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx index be6c72eef6f9a1..8c6a16dcd4a02a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.test.tsx @@ -56,9 +56,11 @@ describe('health check', () => { }); it('renders children if keys are enabled', async () => { - useKibanaMock().services.http.get = jest - .fn() - .mockResolvedValue({ isSufficientlySecure: true, hasPermanentEncryptionKey: true }); + useKibanaMock().services.http.get = jest.fn().mockResolvedValue({ + isSufficientlySecure: true, + hasPermanentEncryptionKey: true, + isAlertsAvailable: true, + }); const { queryByText } = render( @@ -72,10 +74,11 @@ describe('health check', () => { expect(queryByText('should render')).toBeInTheDocument(); }); - test('renders warning if keys are disabled', async () => { - useKibanaMock().services.http.get = jest.fn().mockImplementationOnce(async () => ({ + test('renders warning if TLS is required', async () => { + useKibanaMock().services.http.get = jest.fn().mockImplementation(async () => ({ isSufficientlySecure: false, hasPermanentEncryptionKey: true, + isAlertsAvailable: true, })); const { queryAllByText } = render( @@ -104,9 +107,10 @@ describe('health check', () => { }); test('renders warning if encryption key is ephemeral', async () => { - useKibanaMock().services.http.get = jest.fn().mockImplementationOnce(async () => ({ + useKibanaMock().services.http.get = jest.fn().mockImplementation(async () => ({ isSufficientlySecure: true, hasPermanentEncryptionKey: false, + isAlertsAvailable: true, })); const { queryByText, queryByRole } = render( @@ -121,7 +125,7 @@ describe('health check', () => { const description = queryByRole(/banner/i); expect(description!.textContent).toMatchInlineSnapshot( - `"To create an alert, set a value for xpack.encryptedSavedObjects.encryptionKey in your kibana.yml file. Learn how.(opens in a new tab or window)"` + `"To create an alert, set a value for xpack.encryptedSavedObjects.encryptionKey in your kibana.yml file and ensure the Encrypted Saved Objects plugin is enabled. Learn how.(opens in a new tab or window)"` ); const action = queryByText(/Learn/i); @@ -132,9 +136,10 @@ describe('health check', () => { }); test('renders warning if encryption key is ephemeral and keys are disabled', async () => { - useKibanaMock().services.http.get = jest.fn().mockImplementationOnce(async () => ({ + useKibanaMock().services.http.get = jest.fn().mockImplementation(async () => ({ isSufficientlySecure: false, hasPermanentEncryptionKey: false, + isAlertsAvailable: true, })); const { queryByText } = render( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.tsx index 66f7c1d36dfb21..3103d8f2a817c9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/components/health_check.tsx @@ -14,18 +14,24 @@ import { i18n } from '@kbn/i18n'; import { EuiEmptyPrompt, EuiCode } from '@elastic/eui'; import { DocLinksStart } from 'kibana/public'; -import { AlertingFrameworkHealth } from '../../types'; -import { health } from '../lib/alert_api'; +import { alertingFrameworkHealth } from '../lib/alert_api'; import './health_check.scss'; import { useHealthContext } from '../context/health_context'; import { useKibana } from '../../common/lib/kibana'; import { CenterJustifiedSpinner } from './center_justified_spinner'; +import { triggersActionsUiHealth } from '../../common/lib/health_api'; interface Props { inFlyout?: boolean; waitForCheck: boolean; } +interface HealthStatus { + isAlertsAvailable: boolean; + isSufficientlySecure: boolean; + hasPermanentEncryptionKey: boolean; +} + export const HealthCheck: React.FunctionComponent = ({ children, waitForCheck, @@ -33,12 +39,24 @@ export const HealthCheck: React.FunctionComponent = ({ }) => { const { http, docLinks } = useKibana().services; const { setLoadingHealthCheck } = useHealthContext(); - const [alertingHealth, setAlertingHealth] = React.useState>(none); + const [alertingHealth, setAlertingHealth] = React.useState>(none); React.useEffect(() => { (async function () { setLoadingHealthCheck(true); - setAlertingHealth(some(await health({ http }))); + const triggersActionsUiHealthStatus = await triggersActionsUiHealth({ http }); + const healthStatus: HealthStatus = { + ...triggersActionsUiHealthStatus, + isSufficientlySecure: false, + hasPermanentEncryptionKey: false, + }; + if (healthStatus.isAlertsAvailable) { + const alertingHealthResult = await alertingFrameworkHealth({ http }); + healthStatus.isSufficientlySecure = alertingHealthResult.isSufficientlySecure; + healthStatus.hasPermanentEncryptionKey = alertingHealthResult.hasPermanentEncryptionKey; + } + + setAlertingHealth(some(healthStatus)); setLoadingHealthCheck(false); })(); }, [http, setLoadingHealthCheck]); @@ -60,6 +78,8 @@ export const HealthCheck: React.FunctionComponent = ({ (healthCheck) => { return healthCheck?.isSufficientlySecure && healthCheck?.hasPermanentEncryptionKey ? ( {children} + ) : !healthCheck.isAlertsAvailable ? ( + ) : !healthCheck.isSufficientlySecure && !healthCheck.hasPermanentEncryptionKey ? ( ) : !healthCheck.hasPermanentEncryptionKey ? ( @@ -77,7 +97,7 @@ interface PromptErrorProps { className?: string; } -const TlsAndEncryptionError = ({ +const EncryptionError = ({ // eslint-disable-next-line @typescript-eslint/naming-convention docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION }, className, @@ -90,27 +110,37 @@ const TlsAndEncryptionError = ({ title={

} body={

- {i18n.translate('xpack.triggersActionsUI.components.healthCheck.tlsAndEncryptionError', { - defaultMessage: - 'You must enable Transport Layer Security between Kibana and Elasticsearch and configure an encryption key in your kibana.yml file. ', - })} + {i18n.translate( + 'xpack.triggersActionsUI.components.healthCheck.encryptionErrorBeforeKey', + { + defaultMessage: 'To create an alert, set a value for ', + } + )} + {'xpack.encryptedSavedObjects.encryptionKey'} + {i18n.translate( + 'xpack.triggersActionsUI.components.healthCheck.encryptionErrorAfterKey', + { + defaultMessage: + ' in your kibana.yml file and ensure the Encrypted Saved Objects plugin is enabled. ', + } + )} {i18n.translate( - 'xpack.triggersActionsUI.components.healthCheck.tlsAndEncryptionErrorAction', + 'xpack.triggersActionsUI.components.healthCheck.encryptionErrorAction', { - defaultMessage: 'Learn how', + defaultMessage: 'Learn how.', } )} @@ -120,7 +150,7 @@ const TlsAndEncryptionError = ({ /> ); -const EncryptionError = ({ +const TlsError = ({ // eslint-disable-next-line @typescript-eslint/naming-convention docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION }, className, @@ -133,38 +163,26 @@ const EncryptionError = ({ title={

} body={

- {i18n.translate( - 'xpack.triggersActionsUI.components.healthCheck.encryptionErrorBeforeKey', - { - defaultMessage: 'To create an alert, set a value for ', - } - )} - {'xpack.encryptedSavedObjects.encryptionKey'} - {i18n.translate( - 'xpack.triggersActionsUI.components.healthCheck.encryptionErrorAfterKey', - { - defaultMessage: ' in your kibana.yml file. ', - } - )} + {i18n.translate('xpack.triggersActionsUI.components.healthCheck.tlsError', { + defaultMessage: + 'Alerting relies on API keys, which require TLS between Elasticsearch and Kibana. ', + })} - {i18n.translate( - 'xpack.triggersActionsUI.components.healthCheck.encryptionErrorAction', - { - defaultMessage: 'Learn how.', - } - )} + {i18n.translate('xpack.triggersActionsUI.components.healthCheck.tlsErrorAction', { + defaultMessage: 'Learn how to enable TLS.', + })}

@@ -172,7 +190,46 @@ const EncryptionError = ({ /> ); -const TlsError = ({ +const AlertsError = ({ + // eslint-disable-next-line @typescript-eslint/naming-convention + docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION }, + className, +}: PromptErrorProps) => ( + + + + } + body={ +
+

+ {i18n.translate('xpack.triggersActionsUI.components.healthCheck.alertsError', { + defaultMessage: 'To create an alert, set alerts and actions plugins enabled. ', + })} + + {i18n.translate('xpack.triggersActionsUI.components.healthCheck.alertsErrorAction', { + defaultMessage: 'Learn how to enable Alerts and Actions.', + })} + +

+
+ } + /> +); + +const TlsAndEncryptionError = ({ // eslint-disable-next-line @typescript-eslint/naming-convention docLinks: { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION }, className, @@ -185,26 +242,29 @@ const TlsError = ({ title={

} body={

- {i18n.translate('xpack.triggersActionsUI.components.healthCheck.tlsError', { + {i18n.translate('xpack.triggersActionsUI.components.healthCheck.tlsAndEncryptionError', { defaultMessage: - 'Alerting relies on API keys, which require TLS between Elasticsearch and Kibana. ', + 'You must enable Transport Layer Security between Kibana and Elasticsearch and configure an encryption key in your kibana.yml file. ', })} - {i18n.translate('xpack.triggersActionsUI.components.healthCheck.tlsErrorAction', { - defaultMessage: 'Learn how to enable TLS.', - })} + {i18n.translate( + 'xpack.triggersActionsUI.components.healthCheck.tlsAndEncryptionErrorAction', + { + defaultMessage: 'Learn how', + } + )}

diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts index ea654bb21e88b9..f3d49c52855ab8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.test.ts @@ -25,7 +25,7 @@ import { updateAlert, muteAlertInstance, unmuteAlertInstance, - health, + alertingFrameworkHealth, mapFiltersToKql, } from './alert_api'; import uuid from 'uuid'; @@ -801,9 +801,9 @@ describe('unmuteAlerts', () => { }); }); -describe('health', () => { - test('should call health API', async () => { - const result = await health({ http }); +describe('alertingFrameworkHealth', () => { + test('should call alertingFrameworkHealth API', async () => { + const result = await alertingFrameworkHealth({ http }); expect(result).toEqual(undefined); expect(http.get.mock.calls).toMatchInlineSnapshot(` Array [ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts index 52ab33566da74d..f774b3d35bb290 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/alert_api.ts @@ -282,6 +282,10 @@ export async function unmuteAlerts({ await Promise.all(ids.map((id) => unmuteAlert({ id, http }))); } -export async function health({ http }: { http: HttpSetup }): Promise { +export async function alertingFrameworkHealth({ + http, +}: { + http: HttpSetup; +}): Promise { return await http.get(`${BASE_ALERT_API_PATH}/_health`); } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx index 889dfe8289b130..3c32b5bc729dd6 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_add.test.tsx @@ -25,7 +25,14 @@ jest.mock('../../../common/lib/kibana'); jest.mock('../../lib/alert_api', () => ({ loadAlertTypes: jest.fn(), - health: jest.fn(() => ({ isSufficientlySecure: true, hasPermanentEncryptionKey: true })), + alertingFrameworkHealth: jest.fn(() => ({ + isSufficientlySecure: true, + hasPermanentEncryptionKey: true, + })), +})); + +jest.mock('../../../common/lib/health_api', () => ({ + triggersActionsUiHealth: jest.fn(() => ({ isAlertsAvailable: true })), })); const actionTypeRegistry = actionTypeRegistryMock.create(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx index baf0f55c415dbe..df7729bb407b32 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_form/alert_edit.test.tsx @@ -18,11 +18,25 @@ import { alertTypeRegistryMock } from '../../alert_type_registry.mock'; import { ReactWrapper } from 'enzyme'; import AlertEdit from './alert_edit'; import { useKibana } from '../../../common/lib/kibana'; +import { ALERTS_FEATURE_ID } from '../../../../../alerts/common'; jest.mock('../../../common/lib/kibana'); const actionTypeRegistry = actionTypeRegistryMock.create(); const alertTypeRegistry = alertTypeRegistryMock.create(); const useKibanaMock = useKibana as jest.Mocked; +jest.mock('../../lib/alert_api', () => ({ + loadAlertTypes: jest.fn(), + updateAlert: jest.fn().mockRejectedValue({ body: { message: 'Fail message' } }), + alertingFrameworkHealth: jest.fn(() => ({ + isSufficientlySecure: true, + hasPermanentEncryptionKey: true, + })), +})); + +jest.mock('../../../common/lib/health_api', () => ({ + triggersActionsUiHealth: jest.fn(() => ({ isAlertsAvailable: true })), +})); + describe('alert_edit', () => { let wrapper: ReactWrapper; let mockedCoreSetup: ReturnType; @@ -48,12 +62,32 @@ describe('alert_edit', () => { }, }; - // eslint-disable-next-line react-hooks/rules-of-hooks - useKibanaMock().services.http.get = jest.fn().mockResolvedValue({ - isSufficientlySecure: true, - hasPermanentEncryptionKey: true, - }); - + const { loadAlertTypes } = jest.requireMock('../../lib/alert_api'); + const alertTypes = [ + { + id: 'my-alert-type', + name: 'Test', + actionGroups: [ + { + id: 'testActionGroup', + name: 'Test Action Group', + }, + ], + defaultActionGroupId: 'testActionGroup', + minimumLicenseRequired: 'basic', + recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, + producer: ALERTS_FEATURE_ID, + authorizedConsumers: { + [ALERTS_FEATURE_ID]: { read: true, all: true }, + test: { read: true, all: true }, + }, + actionVariables: { + context: [], + state: [], + params: [], + }, + }, + ]; const alertType = { id: 'my-alert-type', iconClass: 'test', @@ -79,7 +113,7 @@ describe('alert_edit', () => { }, actionConnectorFields: null, }); - + loadAlertTypes.mockResolvedValue(alertTypes); const alert: Alert = { id: 'ab5661e0-197e-45ee-b477-302d89193b5e', params: { @@ -145,19 +179,15 @@ describe('alert_edit', () => { }); } - it('renders alert add flyout', async () => { + it('renders alert edit flyout', async () => { await setup(); expect(wrapper.find('[data-test-subj="editAlertFlyoutTitle"]').exists()).toBeTruthy(); expect(wrapper.find('[data-test-subj="saveEditedAlertButton"]').exists()).toBeTruthy(); }); it('displays a toast message on save for server errors', async () => { - useKibanaMock().services.http.get = jest.fn().mockResolvedValue([]); await setup(); - const err = new Error() as any; - err.body = {}; - err.body.message = 'Fail message'; - useKibanaMock().services.http.put = jest.fn().mockRejectedValue(err); + await act(async () => { wrapper.find('[data-test-subj="saveEditedAlertButton"]').first().simulate('click'); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx index 8ca3edb1c68df3..bd50bf3270f1a3 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_list/components/alerts_list.test.tsx @@ -26,7 +26,13 @@ jest.mock('../../../lib/action_connector_api', () => ({ jest.mock('../../../lib/alert_api', () => ({ loadAlerts: jest.fn(), loadAlertTypes: jest.fn(), - health: jest.fn(() => ({ isSufficientlySecure: true, hasPermanentEncryptionKey: true })), + alertingFrameworkHealth: jest.fn(() => ({ + isSufficientlySecure: true, + hasPermanentEncryptionKey: true, + })), +})); +jest.mock('../../../../common/lib/health_api', () => ({ + triggersActionsUiHealth: jest.fn(() => ({ isAlertsAvailable: true })), })); jest.mock('react-router-dom', () => ({ useHistory: () => ({ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx index 5656aa9de7795f..f44f6e87c7a190 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_alert_api_operations.tsx @@ -29,7 +29,7 @@ import { loadAlertState, loadAlertInstanceSummary, loadAlertTypes, - health, + alertingFrameworkHealth, } from '../../../lib/alert_api'; import { useKibana } from '../../../../common/lib/kibana'; @@ -131,7 +131,7 @@ export function withBulkAlertOperations( loadAlertInstanceSummary({ http, alertId }) } loadAlertTypes={async () => loadAlertTypes({ http })} - getHealth={async () => health({ http })} + getHealth={async () => alertingFrameworkHealth({ http })} /> ); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/common/lib/health_api.test.ts b/x-pack/plugins/triggers_actions_ui/public/common/lib/health_api.test.ts new file mode 100644 index 00000000000000..d22fd538ad0cac --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/common/lib/health_api.test.ts @@ -0,0 +1,24 @@ +/* + * 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 { httpServiceMock } from 'src/core/public/mocks'; +import { triggersActionsUiHealth } from './health_api'; + +describe('triggersActionsUiHealth', () => { + const http = httpServiceMock.createStartContract(); + + test('should call triggersActionsUiHealth API', async () => { + const result = await triggersActionsUiHealth({ http }); + expect(result).toEqual(undefined); + expect(http.get.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/api/triggers_actions_ui/_health", + ], + ] + `); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/common/lib/health_api.ts b/x-pack/plugins/triggers_actions_ui/public/common/lib/health_api.ts new file mode 100644 index 00000000000000..752f5b3e2ca08f --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/common/lib/health_api.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { HttpSetup } from 'kibana/public'; + +const TRIGGERS_ACTIONS_UI_API_ROOT = '/api/triggers_actions_ui'; + +export async function triggersActionsUiHealth({ http }: { http: HttpSetup }): Promise { + return await http.get(`${TRIGGERS_ACTIONS_UI_API_ROOT}/_health`); +} diff --git a/x-pack/plugins/triggers_actions_ui/server/data/routes/fields.ts b/x-pack/plugins/triggers_actions_ui/server/data/routes/fields.ts index 17a2b2929f0cf4..2cda40c18db0ca 100644 --- a/x-pack/plugins/triggers_actions_ui/server/data/routes/fields.ts +++ b/x-pack/plugins/triggers_actions_ui/server/data/routes/fields.ts @@ -4,9 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -// the business logic of this code is from watcher, in: -// x-pack/plugins/watcher/server/routes/api/register_list_fields_route.ts - import { schema, TypeOf } from '@kbn/config-schema'; import { IRouter, diff --git a/x-pack/plugins/triggers_actions_ui/server/plugin.ts b/x-pack/plugins/triggers_actions_ui/server/plugin.ts index c0d29341e217bb..69be37f6658875 100644 --- a/x-pack/plugins/triggers_actions_ui/server/plugin.ts +++ b/x-pack/plugins/triggers_actions_ui/server/plugin.ts @@ -5,12 +5,21 @@ */ import { Logger, Plugin, CoreSetup, PluginInitializerContext } from 'src/core/server'; +import { PluginSetupContract as AlertsPluginSetup } from '../../alerts/server'; +import { EncryptedSavedObjectsPluginSetup } from '../../encrypted_saved_objects/server'; import { getService, register as registerDataService } from './data'; +import { createHealthRoute } from './routes/health'; +const BASE_ROUTE = '/api/triggers_actions_ui'; export interface PluginStartContract { data: ReturnType; } +interface PluginsSetup { + encryptedSavedObjects?: EncryptedSavedObjectsPluginSetup; + alerts?: AlertsPluginSetup; +} + export class TriggersActionsPlugin implements Plugin { private readonly logger: Logger; private readonly data: PluginStartContract['data']; @@ -20,13 +29,16 @@ export class TriggersActionsPlugin implements Plugin this.data = getService(); } - public async setup(core: CoreSetup): Promise { + public async setup(core: CoreSetup, plugins: PluginsSetup): Promise { + const router = core.http.createRouter(); registerDataService({ logger: this.logger, data: this.data, - router: core.http.createRouter(), - baseRoute: '/api/triggers_actions_ui', + router, + baseRoute: BASE_ROUTE, }); + + createHealthRoute(this.logger, router, BASE_ROUTE, plugins.alerts !== undefined); } public async start(): Promise { diff --git a/x-pack/plugins/triggers_actions_ui/server/routes/health.ts b/x-pack/plugins/triggers_actions_ui/server/routes/health.ts new file mode 100644 index 00000000000000..1ea9cb748bcd7b --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/server/routes/health.ts @@ -0,0 +1,41 @@ +/* + * 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 { + IRouter, + RequestHandlerContext, + KibanaRequest, + IKibanaResponse, + KibanaResponseFactory, +} from 'kibana/server'; +import { Logger } from '../../../../../src/core/server'; + +export function createHealthRoute( + logger: Logger, + router: IRouter, + baseRoute: string, + isAlertsAvailable: boolean +) { + const path = `${baseRoute}/_health`; + logger.debug(`registering triggers_actions_ui health route GET ${path}`); + router.get( + { + path, + validate: false, + }, + handler + ); + async function handler( + ctx: RequestHandlerContext, + req: KibanaRequest, + res: KibanaResponseFactory + ): Promise { + const result = { isAlertsAvailable }; + + logger.debug(`route ${path} response: ${JSON.stringify(result)}`); + return res.ok({ body: result }); + } +} 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 f23601fccb1747..eee0ec7f9ad38a 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 @@ -8,7 +8,7 @@ Array [ }, Object { "x": 1607435880000, - "y": 4, + "y": 0.133333333333333, }, Object { "x": 1607435910000, @@ -16,7 +16,7 @@ Array [ }, Object { "x": 1607435940000, - "y": 2, + "y": 0.0666666666666667, }, Object { "x": 1607435970000, @@ -24,11 +24,11 @@ Array [ }, Object { "x": 1607436000000, - "y": 3, + "y": 0.1, }, Object { "x": 1607436030000, - "y": 1, + "y": 0.0333333333333333, }, Object { "x": 1607436060000, @@ -40,7 +40,7 @@ Array [ }, Object { "x": 1607436120000, - "y": 4, + "y": 0.133333333333333, }, Object { "x": 1607436150000, @@ -56,7 +56,7 @@ Array [ }, Object { "x": 1607436240000, - "y": 6, + "y": 0.2, }, Object { "x": 1607436270000, @@ -68,15 +68,15 @@ Array [ }, Object { "x": 1607436330000, - "y": 1, + "y": 0.0333333333333333, }, Object { "x": 1607436360000, - "y": 5, + "y": 0.166666666666667, }, Object { "x": 1607436390000, - "y": 1, + "y": 0.0333333333333333, }, Object { "x": 1607436420000, @@ -88,11 +88,11 @@ Array [ }, Object { "x": 1607436480000, - "y": 2, + "y": 0.0666666666666667, }, Object { "x": 1607436510000, - "y": 5, + "y": 0.166666666666667, }, Object { "x": 1607436540000, @@ -104,11 +104,11 @@ Array [ }, Object { "x": 1607436600000, - "y": 2, + "y": 0.0666666666666667, }, Object { "x": 1607436630000, - "y": 7, + "y": 0.233333333333333, }, Object { "x": 1607436660000, @@ -124,7 +124,7 @@ Array [ }, Object { "x": 1607436750000, - "y": 2, + "y": 0.0666666666666667, }, Object { "x": 1607436780000, @@ -132,15 +132,15 @@ Array [ }, Object { "x": 1607436810000, - "y": 1, + "y": 0.0333333333333333, }, Object { "x": 1607436840000, - "y": 1, + "y": 0.0333333333333333, }, Object { "x": 1607436870000, - "y": 2, + "y": 0.0666666666666667, }, Object { "x": 1607436900000, @@ -152,11 +152,11 @@ Array [ }, Object { "x": 1607436960000, - "y": 2, + "y": 0.0666666666666667, }, Object { "x": 1607436990000, - "y": 4, + "y": 0.133333333333333, }, Object { "x": 1607437020000, @@ -168,11 +168,11 @@ Array [ }, Object { "x": 1607437080000, - "y": 1, + "y": 0.0333333333333333, }, Object { "x": 1607437110000, - "y": 1, + "y": 0.0333333333333333, }, Object { "x": 1607437140000, @@ -184,15 +184,15 @@ Array [ }, Object { "x": 1607437200000, - "y": 2, + "y": 0.0666666666666667, }, Object { "x": 1607437230000, - "y": 7, + "y": 0.233333333333333, }, Object { "x": 1607437260000, - "y": 1, + "y": 0.0333333333333333, }, Object { "x": 1607437290000, @@ -200,11 +200,11 @@ Array [ }, Object { "x": 1607437320000, - "y": 1, + "y": 0.0333333333333333, }, Object { "x": 1607437350000, - "y": 2, + "y": 0.0666666666666667, }, Object { "x": 1607437380000, @@ -216,11 +216,11 @@ Array [ }, Object { "x": 1607437440000, - "y": 1, + "y": 0.0333333333333333, }, Object { "x": 1607437470000, - "y": 3, + "y": 0.1, }, Object { "x": 1607437500000, @@ -232,7 +232,7 @@ Array [ }, Object { "x": 1607437560000, - "y": 1, + "y": 0.0333333333333333, }, Object { "x": 1607437590000,