diff --git a/x-pack/plugins/alerting/README.md b/x-pack/plugins/alerting/README.md index 6332985112c4c..19322fed7363e 100644 --- a/x-pack/plugins/alerting/README.md +++ b/x-pack/plugins/alerting/README.md @@ -116,9 +116,8 @@ This is the primary function for an alert type. Whenever the alert needs to exec |Property|Description| |---|---| -|services.callCluster(path, opts)|Use this to do Elasticsearch queries on the cluster Kibana connects to. This function is the same as any other `callCluster` in Kibana but in the context of the user who created the alert when security is enabled.| +|services.scopedClusterClient|This is an instance of the Elasticsearch client. Use this to do Elasticsearch queries in the context of the user who created the alert when security is enabled.| |services.savedObjectsClient|This is an instance of the saved objects client. This provides the ability to do CRUD on any saved objects within the same space the alert lives in.

The scope of the saved objects client is tied to the user who created the alert (only when security isenabled).| -|services.getLegacyScopedClusterClient|This function returns an instance of the LegacyScopedClusterClient scoped to the user who created the alert when security is enabled.| |services.alertInstanceFactory(id)|This [alert instance factory](#alert-instance-factory) creates instances of alerts and must be used in order to execute actions. The id you give to the alert instance factory is a unique identifier to the alert instance.| |services.log(tags, [data], [timestamp])|Use this to create server logs. (This is the same function as server.log)| |startedAt|The date and time the alert type started execution.| diff --git a/x-pack/plugins/alerting/server/mocks.ts b/x-pack/plugins/alerting/server/mocks.ts index f3c40a6788967..df9a3c5ddf169 100644 --- a/x-pack/plugins/alerting/server/mocks.ts +++ b/x-pack/plugins/alerting/server/mocks.ts @@ -70,10 +70,8 @@ const createAlertServicesMock = < alertInstanceFactory: jest .fn>, [string]>() .mockReturnValue(alertInstanceFactoryMock), - callCluster: elasticsearchServiceMock.createLegacyScopedClusterClient().callAsCurrentUser, - getLegacyScopedClusterClient: jest.fn(), savedObjectsClient: savedObjectsClientMock.create(), - scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient().asCurrentUser, + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), }; }; export type AlertServicesMock = ReturnType; diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index d85622f301171..ff36ebcd84ba5 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -31,7 +31,6 @@ import { SavedObjectsServiceStart, IContextProvider, ElasticsearchServiceStart, - ILegacyClusterClient, StatusServiceSetup, ServiceStatus, SavedObjectsBulkGetObject, @@ -420,12 +419,8 @@ export class AlertingPlugin { elasticsearch: ElasticsearchServiceStart ): (request: KibanaRequest) => Services { return (request) => ({ - callCluster: elasticsearch.legacy.client.asScoped(request).callAsCurrentUser, savedObjectsClient: this.getScopedClientWithAlertSavedObjectType(savedObjects, request), - scopedClusterClient: elasticsearch.client.asScoped(request).asCurrentUser, - getLegacyScopedClusterClient(clusterClient: ILegacyClusterClient) { - return clusterClient.asScoped(request); - }, + scopedClusterClient: elasticsearch.client.asScoped(request), }); } diff --git a/x-pack/plugins/alerting/server/routes/_mock_handler_arguments.ts b/x-pack/plugins/alerting/server/routes/_mock_handler_arguments.ts index a5cc192a337b7..cd1c32a9b2d8f 100644 --- a/x-pack/plugins/alerting/server/routes/_mock_handler_arguments.ts +++ b/x-pack/plugins/alerting/server/routes/_mock_handler_arguments.ts @@ -5,9 +5,11 @@ * 2.0. */ -import { KibanaRequest, KibanaResponseFactory, ILegacyClusterClient } from 'kibana/server'; +import { KibanaRequest, KibanaResponseFactory } from 'kibana/server'; import { identity } from 'lodash'; import type { MethodKeysOf } from '@kbn/utility-types'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { ScopedClusterClientMock } from '../../../../../src/core/server/elasticsearch/client/mocks'; import { httpServerMock } from '../../../../../src/core/server/mocks'; import { alertsClientMock, AlertsClientMock } from '../alerts_client.mock'; import { AlertsHealth, AlertType } from '../../common'; @@ -18,12 +20,12 @@ export function mockHandlerArguments( { alertsClient = alertsClientMock.create(), listTypes: listTypesRes = [], - esClient = elasticsearchServiceMock.createLegacyClusterClient(), + esClient = elasticsearchServiceMock.createScopedClusterClient(), getFrameworkHealth, }: { alertsClient?: AlertsClientMock; listTypes?: AlertType[]; - esClient?: jest.Mocked; + esClient?: jest.Mocked; getFrameworkHealth?: jest.MockInstance, []> & (() => Promise); }, @@ -37,7 +39,7 @@ export function mockHandlerArguments( const listTypes = jest.fn(() => listTypesRes); return [ ({ - core: { elasticsearch: { legacy: { client: esClient } } }, + core: { elasticsearch: { client: esClient } }, alerting: { listTypes, getAlertsClient() { diff --git a/x-pack/plugins/alerting/server/routes/health.test.ts b/x-pack/plugins/alerting/server/routes/health.test.ts index 22df0e6a00046..75c621e4a0abf 100644 --- a/x-pack/plugins/alerting/server/routes/health.test.ts +++ b/x-pack/plugins/alerting/server/routes/health.test.ts @@ -15,6 +15,8 @@ import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/serv import { alertsClientMock } from '../alerts_client.mock'; import { HealthStatus } from '../types'; import { alertsMock } from '../mocks'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../src/core/server/elasticsearch/client/mocks'; const alertsClient = alertsClientMock.create(); jest.mock('../lib/license_api_access.ts', () => ({ @@ -63,8 +65,10 @@ describe('healthRoute', () => { healthRoute(router, licenseState, encryptedSavedObjects); const [, handler] = router.get.mock.calls[0]; - const esClient = elasticsearchServiceMock.createLegacyClusterClient(); - esClient.callAsInternalUser.mockReturnValue(Promise.resolve({})); + const esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asInternalUser.transport.request.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({}) + ); const [context, req, res] = mockHandlerArguments({ esClient, alertsClient }, {}, ['ok']); @@ -72,9 +76,8 @@ describe('healthRoute', () => { expect(verifyApiAccess).toHaveBeenCalledWith(licenseState); - expect(esClient.callAsInternalUser.mock.calls[0]).toMatchInlineSnapshot(` + expect(esClient.asInternalUser.transport.request.mock.calls[0]).toMatchInlineSnapshot(` Array [ - "transport.request", Object { "method": "GET", "path": "/_xpack/usage", @@ -91,8 +94,10 @@ describe('healthRoute', () => { healthRoute(router, licenseState, encryptedSavedObjects); const [, handler] = router.get.mock.calls[0]; - const esClient = elasticsearchServiceMock.createLegacyClusterClient(); - esClient.callAsInternalUser.mockReturnValue(Promise.resolve({})); + const esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asInternalUser.transport.request.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({}) + ); const [context, req, res] = mockHandlerArguments( { esClient, alertsClient, getFrameworkHealth: alerting.getFrameworkHealth }, @@ -130,8 +135,10 @@ describe('healthRoute', () => { healthRoute(router, licenseState, encryptedSavedObjects); const [, handler] = router.get.mock.calls[0]; - const esClient = elasticsearchServiceMock.createLegacyClusterClient(); - esClient.callAsInternalUser.mockReturnValue(Promise.resolve({})); + const esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asInternalUser.transport.request.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({}) + ); const [context, req, res] = mockHandlerArguments( { esClient, alertsClient, getFrameworkHealth: alerting.getFrameworkHealth }, @@ -169,8 +176,10 @@ describe('healthRoute', () => { healthRoute(router, licenseState, encryptedSavedObjects); const [, handler] = router.get.mock.calls[0]; - const esClient = elasticsearchServiceMock.createLegacyClusterClient(); - esClient.callAsInternalUser.mockReturnValue(Promise.resolve({ security: {} })); + const esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asInternalUser.transport.request.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ security: {} }) + ); const [context, req, res] = mockHandlerArguments( { esClient, alertsClient, getFrameworkHealth: alerting.getFrameworkHealth }, @@ -208,8 +217,10 @@ describe('healthRoute', () => { healthRoute(router, licenseState, encryptedSavedObjects); const [, handler] = router.get.mock.calls[0]; - const esClient = elasticsearchServiceMock.createLegacyClusterClient(); - esClient.callAsInternalUser.mockReturnValue(Promise.resolve({ security: { enabled: true } })); + const esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asInternalUser.transport.request.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ security: { enabled: true } }) + ); const [context, req, res] = mockHandlerArguments( { esClient, alertsClient, getFrameworkHealth: alerting.getFrameworkHealth }, @@ -247,9 +258,11 @@ describe('healthRoute', () => { healthRoute(router, licenseState, encryptedSavedObjects); const [, handler] = router.get.mock.calls[0]; - const esClient = elasticsearchServiceMock.createLegacyClusterClient(); - esClient.callAsInternalUser.mockReturnValue( - Promise.resolve({ security: { enabled: true, ssl: {} } }) + const esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asInternalUser.transport.request.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + security: { enabled: true, ssl: {} }, + }) ); const [context, req, res] = mockHandlerArguments( @@ -288,9 +301,11 @@ describe('healthRoute', () => { healthRoute(router, licenseState, encryptedSavedObjects); const [, handler] = router.get.mock.calls[0]; - const esClient = elasticsearchServiceMock.createLegacyClusterClient(); - esClient.callAsInternalUser.mockReturnValue( - Promise.resolve({ security: { enabled: true, ssl: { http: { enabled: true } } } }) + const esClient = elasticsearchServiceMock.createScopedClusterClient(); + esClient.asInternalUser.transport.request.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + security: { enabled: true, ssl: { http: { enabled: true } } }, + }) ); const [context, req, res] = mockHandlerArguments( diff --git a/x-pack/plugins/alerting/server/routes/health.ts b/x-pack/plugins/alerting/server/routes/health.ts index 9e1f01041e091..de0b14465c5ac 100644 --- a/x-pack/plugins/alerting/server/routes/health.ts +++ b/x-pack/plugins/alerting/server/routes/health.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { ApiResponse } from '@elastic/elasticsearch'; import type { AlertingRouter } from '../types'; import { ILicenseState } from '../lib/license_state'; import { verifyApiAccess } from '../lib/license_api_access'; @@ -39,14 +40,14 @@ export function healthRoute( } try { const { - security: { - enabled: isSecurityEnabled = false, - ssl: { http: { enabled: isTLSEnabled = false } = {} } = {}, - } = {}, - }: XPackUsageSecurity = await context.core.elasticsearch.legacy.client - // `transport.request` is potentially unsafe when combined with untrusted user input. - // Do not augment with such input. - .callAsInternalUser('transport.request', { + body: { + security: { + enabled: isSecurityEnabled = false, + ssl: { http: { enabled: isTLSEnabled = false } = {} } = {}, + } = {}, + }, + }: ApiResponse = await context.core.elasticsearch.client.asInternalUser.transport // Do not augment with such input. // `transport.request` is potentially unsafe when combined with untrusted user input. + .request({ method: 'GET', path: '/_xpack/usage', }); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index bb5e0e5830159..a3a7e9bbd9da5 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -206,7 +206,7 @@ describe('Task Runner', () => { expect(call.createdBy).toBe('alert-creator'); expect(call.updatedBy).toBe('alert-updater'); expect(call.services.alertInstanceFactory).toBeTruthy(); - expect(call.services.callCluster).toBeTruthy(); + expect(call.services.scopedClusterClient).toBeTruthy(); expect(call.services).toBeTruthy(); const logger = taskRunnerFactoryInitializerParams.logger; diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index 2b749b866d3a0..23aed1070a31a 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -13,9 +13,7 @@ import { PluginSetupContract, PluginStartContract } from './plugin'; import { AlertsClient } from './alerts_client'; export * from '../common'; import { - ElasticsearchClient, - ILegacyClusterClient, - ILegacyScopedClusterClient, + IScopedClusterClient, KibanaRequest, SavedObjectAttributes, SavedObjectsClientContract, @@ -63,13 +61,8 @@ export interface AlertingRequestHandlerContext extends RequestHandlerContext { export type AlertingRouter = IRouter; export interface Services { - /** - * @deprecated Use `scopedClusterClient` instead. - */ - callCluster: ILegacyScopedClusterClient['callAsCurrentUser']; savedObjectsClient: SavedObjectsClientContract; - scopedClusterClient: ElasticsearchClient; - getLegacyScopedClusterClient(clusterClient: ILegacyClusterClient): ILegacyScopedClusterClient; + scopedClusterClient: IScopedClusterClient; } export interface AlertServices< diff --git a/x-pack/plugins/alerting/server/usage/alerts_telemetry.test.ts b/x-pack/plugins/alerting/server/usage/alerts_telemetry.test.ts index 8a3870c894e4e..3c9decdf7ba96 100644 --- a/x-pack/plugins/alerting/server/usage/alerts_telemetry.test.ts +++ b/x-pack/plugins/alerting/server/usage/alerts_telemetry.test.ts @@ -5,27 +5,31 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../src/core/server/elasticsearch/client/mocks'; import { getTotalCountInUse } from './alerts_telemetry'; describe('alerts telemetry', () => { test('getTotalCountInUse should replace first "." symbol to "__" in alert types names', async () => { - const mockEsClient = jest.fn(); - mockEsClient.mockReturnValue({ - aggregations: { - byAlertTypeId: { - value: { - types: { '.index-threshold': 2, 'logs.alert.document.count': 1, 'document.test.': 1 }, + const mockEsClient = elasticsearchClientMock.createClusterClient().asScoped().asInternalUser; + mockEsClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + aggregations: { + byAlertTypeId: { + value: { + types: { '.index-threshold': 2, 'logs.alert.document.count': 1, 'document.test.': 1 }, + }, }, }, - }, - hits: { - hits: [], - }, - }); + hits: { + hits: [], + }, + }) + ); const telemetry = await getTotalCountInUse(mockEsClient, 'test'); - expect(mockEsClient).toHaveBeenCalledTimes(1); + expect(mockEsClient.search).toHaveBeenCalledTimes(1); expect(telemetry).toMatchInlineSnapshot(` Object { diff --git a/x-pack/plugins/alerting/server/usage/alerts_telemetry.ts b/x-pack/plugins/alerting/server/usage/alerts_telemetry.ts index c66110f2647c6..93bed31ce7d50 100644 --- a/x-pack/plugins/alerting/server/usage/alerts_telemetry.ts +++ b/x-pack/plugins/alerting/server/usage/alerts_telemetry.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; -import { SearchResponse } from 'elasticsearch'; +import { ElasticsearchClient } from 'kibana/server'; import { AlertsUsage } from './types'; const alertTypeMetric = { @@ -36,7 +35,7 @@ const alertTypeMetric = { }; export async function getTotalCountAggregations( - callCluster: LegacyAPICaller, + esClient: ElasticsearchClient, kibanaInex: string ): Promise< Pick< @@ -223,7 +222,7 @@ export async function getTotalCountAggregations( }, }; - const results = await callCluster('search', { + const { body: results } = await esClient.search({ index: kibanaInex, body: { query: { @@ -256,7 +255,7 @@ export async function getTotalCountAggregations( return { count_total: totalAlertsCount, count_by_type: Object.keys(results.aggregations.byAlertTypeId.value.types).reduce( - // ES DSL aggregations are returned as `any` by callCluster + // ES DSL aggregations are returned as `any` by esClient.search // eslint-disable-next-line @typescript-eslint/no-explicit-any (obj: any, key: string) => ({ ...obj, @@ -295,8 +294,8 @@ export async function getTotalCountAggregations( }; } -export async function getTotalCountInUse(callCluster: LegacyAPICaller, kibanaInex: string) { - const searchResult: SearchResponse = await callCluster('search', { +export async function getTotalCountInUse(esClient: ElasticsearchClient, kibanaInex: string) { + const { body: searchResult } = await esClient.search({ index: kibanaInex, body: { query: { @@ -316,7 +315,7 @@ export async function getTotalCountInUse(callCluster: LegacyAPICaller, kibanaIne 0 ), countByType: Object.keys(searchResult.aggregations.byAlertTypeId.value.types).reduce( - // ES DSL aggregations are returned as `any` by callCluster + // ES DSL aggregations are returned as `any` by esClient.search // eslint-disable-next-line @typescript-eslint/no-explicit-any (obj: any, key: string) => ({ ...obj, diff --git a/x-pack/plugins/alerting/server/usage/task.ts b/x-pack/plugins/alerting/server/usage/task.ts index d03697f2bb11b..043d970ddd231 100644 --- a/x-pack/plugins/alerting/server/usage/task.ts +++ b/x-pack/plugins/alerting/server/usage/task.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Logger, CoreSetup, LegacyAPICaller } from 'kibana/server'; +import { Logger, CoreSetup } from 'kibana/server'; import moment from 'moment'; import { RunContext, @@ -65,17 +65,21 @@ async function scheduleTasks(logger: Logger, taskManager: TaskManagerStartContra export function telemetryTaskRunner(logger: Logger, core: CoreSetup, kibanaIndex: string) { return ({ taskInstance }: RunContext) => { const { state } = taskInstance; - const callCluster = (...args: Parameters) => { - return core.getStartServices().then(([{ elasticsearch: { legacy: { client } } }]) => - client.callAsInternalUser(...args) + const getEsClient = () => + core.getStartServices().then( + ([ + { + elasticsearch: { client }, + }, + ]) => client.asInternalUser ); - }; return { async run() { + const esClient = await getEsClient(); return Promise.all([ - getTotalCountAggregations(callCluster, kibanaIndex), - getTotalCountInUse(callCluster, kibanaIndex), + getTotalCountAggregations(esClient, kibanaIndex), + getTotalCountInUse(esClient, kibanaIndex), ]) .then(([totalCountAggregations, totalInUse]) => { return { diff --git a/x-pack/plugins/apm/server/lib/alerts/alerting_es_client.ts b/x-pack/plugins/apm/server/lib/alerts/alerting_es_client.ts index d5706ac9063ed..c4fef64f515d1 100644 --- a/x-pack/plugins/apm/server/lib/alerts/alerting_es_client.ts +++ b/x-pack/plugins/apm/server/lib/alerts/alerting_es_client.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { ApiResponse } from '@elastic/elasticsearch'; import { ThresholdMetActionGroupId } from '../../../common/alert_types'; import { ESSearchRequest, @@ -23,8 +24,8 @@ export function alertingEsClient( ThresholdMetActionGroupId >, params: TParams -): Promise> { - return services.callCluster('search', { +): Promise>> { + return services.scopedClusterClient.asCurrentUser.search({ ...params, ignore_unavailable: true, }); diff --git a/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.test.ts b/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.test.ts index 4d403be84a2b2..167cb133102f2 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.test.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.test.ts @@ -13,6 +13,9 @@ import { AlertingPlugin } from '../../../../alerting/server'; import { APMConfig } from '../..'; import { registerErrorCountAlertType } from './register_error_count_alert_type'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; type Operator = (source: Rx.Observable) => Rx.Observable; const pipeClosure = (fn: Operator): Operator => { @@ -43,16 +46,20 @@ describe('Error count alert', () => { expect(alertExecutor).toBeDefined(); const services = { - callCluster: jest.fn(() => ({ + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), + alertInstanceFactory: jest.fn(), + }; + const params = { threshold: 1 }; + + services.scopedClusterClient.asCurrentUser.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ hits: { total: { value: 0, }, }, - })), - alertInstanceFactory: jest.fn(), - }; - const params = { threshold: 1 }; + }) + ); await alertExecutor!({ services, params }); expect(services.alertInstanceFactory).not.toBeCalled(); @@ -74,7 +81,13 @@ describe('Error count alert', () => { const scheduleActions = jest.fn(); const services = { - callCluster: jest.fn(() => ({ + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), + alertInstanceFactory: jest.fn(() => ({ scheduleActions })), + }; + const params = { threshold: 1, windowSize: 5, windowUnit: 'm' }; + + services.scopedClusterClient.asCurrentUser.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ hits: { total: { value: 2, @@ -98,10 +111,8 @@ describe('Error count alert', () => { ], }, }, - })), - alertInstanceFactory: jest.fn(() => ({ scheduleActions })), - }; - const params = { threshold: 1, windowSize: 5, windowUnit: 'm' }; + }) + ); await alertExecutor!({ services, params }); [ @@ -158,7 +169,13 @@ describe('Error count alert', () => { const scheduleActions = jest.fn(); const services = { - callCluster: jest.fn(() => ({ + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), + alertInstanceFactory: jest.fn(() => ({ scheduleActions })), + }; + const params = { threshold: 1, windowSize: 5, windowUnit: 'm' }; + + services.scopedClusterClient.asCurrentUser.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ hits: { total: { value: 2, @@ -176,10 +193,8 @@ describe('Error count alert', () => { ], }, }, - })), - alertInstanceFactory: jest.fn(() => ({ scheduleActions })), - }; - const params = { threshold: 1, windowSize: 5, windowUnit: 'm' }; + }) + ); await alertExecutor!({ services, params }); ['apm.error_rate_foo', 'apm.error_rate_bar'].forEach((instanceName) => diff --git a/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts index 70b41da6917ef..0120891a8f868 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_error_count_alert_type.ts @@ -127,7 +127,7 @@ export function registerErrorCountAlertType({ }, }; - const response = await alertingEsClient(services, searchParams); + const { body: response } = await alertingEsClient(services, searchParams); const errorCount = response.hits.total.value; if (errorCount > alertParams.threshold) { diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts index bb8e67574e9ad..500e0744d5638 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_duration_alert_type.ts @@ -122,7 +122,7 @@ export function registerTransactionDurationAlertType({ }, }; - const response = await alertingEsClient(services, searchParams); + const { body: response } = await alertingEsClient(services, searchParams); if (!response.aggregations) { return; diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.test.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.test.ts index 068eb9b1ccef4..c18f29b6267e0 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.test.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.test.ts @@ -11,6 +11,9 @@ import { toArray, map } from 'rxjs/operators'; import { AlertingPlugin } from '../../../../alerting/server'; import { APMConfig } from '../..'; import { registerTransactionErrorRateAlertType } from './register_transaction_error_rate_alert_type'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; type Operator = (source: Rx.Observable) => Rx.Observable; const pipeClosure = (fn: Operator): Operator => { @@ -41,16 +44,20 @@ describe('Transaction error rate alert', () => { expect(alertExecutor).toBeDefined(); const services = { - callCluster: jest.fn(() => ({ + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), + alertInstanceFactory: jest.fn(), + }; + const params = { threshold: 1 }; + + services.scopedClusterClient.asCurrentUser.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ hits: { total: { value: 0, }, }, - })), - alertInstanceFactory: jest.fn(), - }; - const params = { threshold: 1 }; + }) + ); await alertExecutor!({ services, params }); expect(services.alertInstanceFactory).not.toBeCalled(); @@ -72,7 +79,13 @@ describe('Transaction error rate alert', () => { const scheduleActions = jest.fn(); const services = { - callCluster: jest.fn(() => ({ + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), + alertInstanceFactory: jest.fn(() => ({ scheduleActions })), + }; + const params = { threshold: 10, windowSize: 5, windowUnit: 'm' }; + + services.scopedClusterClient.asCurrentUser.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ hits: { total: { value: 4, @@ -113,10 +126,8 @@ describe('Transaction error rate alert', () => { ], }, }, - })), - alertInstanceFactory: jest.fn(() => ({ scheduleActions })), - }; - const params = { threshold: 10, windowSize: 5, windowUnit: 'm' }; + }) + ); await alertExecutor!({ services, params }); [ @@ -177,7 +188,13 @@ describe('Transaction error rate alert', () => { const scheduleActions = jest.fn(); const services = { - callCluster: jest.fn(() => ({ + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), + alertInstanceFactory: jest.fn(() => ({ scheduleActions })), + }; + const params = { threshold: 10, windowSize: 5, windowUnit: 'm' }; + + services.scopedClusterClient.asCurrentUser.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ hits: { total: { value: 4, @@ -204,10 +221,8 @@ describe('Transaction error rate alert', () => { ], }, }, - })), - alertInstanceFactory: jest.fn(() => ({ scheduleActions })), - }; - const params = { threshold: 10, windowSize: 5, windowUnit: 'm' }; + }) + ); await alertExecutor!({ services, params }); [ @@ -251,7 +266,13 @@ describe('Transaction error rate alert', () => { const scheduleActions = jest.fn(); const services = { - callCluster: jest.fn(() => ({ + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), + alertInstanceFactory: jest.fn(() => ({ scheduleActions })), + }; + const params = { threshold: 10, windowSize: 5, windowUnit: 'm' }; + + services.scopedClusterClient.asCurrentUser.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ hits: { total: { value: 4, @@ -265,10 +286,8 @@ describe('Transaction error rate alert', () => { buckets: [{ key: 'foo' }, { key: 'bar' }], }, }, - })), - alertInstanceFactory: jest.fn(() => ({ scheduleActions })), - }; - const params = { threshold: 10, windowSize: 5, windowUnit: 'm' }; + }) + ); await alertExecutor!({ services, params }); [ diff --git a/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts b/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts index ef5407500349d..0b2684cdaf083 100644 --- a/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts +++ b/x-pack/plugins/apm/server/lib/alerts/register_transaction_error_rate_alert_type.ts @@ -134,7 +134,7 @@ export function registerTransactionErrorRateAlertType({ }, }; - const response = await alertingEsClient(services, searchParams); + const { body: response } = await alertingEsClient(services, searchParams); if (!response.aggregations) { return; } diff --git a/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts index 557831780008a..5784afa31ca4f 100644 --- a/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/framework/kibana_framework_adapter.ts @@ -5,6 +5,13 @@ * 2.0. */ +import { + IndicesExistsAlias, + IndicesGet, + MlGetBuckets, + Msearch, +} from '@elastic/elasticsearch/api/requestParams'; +import { TransportRequestParams } from '@elastic/elasticsearch/lib/Transport'; import { InfraRouteConfig, InfraTSVBResponse, @@ -134,10 +141,58 @@ export class KibanaFramework { } : {}; - return elasticsearch.legacy.client.callAsCurrentUser(endpoint, { - ...params, - ...frozenIndicesParams, - }); + let apiResult; + switch (endpoint) { + case 'search': + apiResult = elasticsearch.client.asCurrentUser.search({ + ...params, + ...frozenIndicesParams, + } as any); + break; + case 'msearch': + apiResult = elasticsearch.client.asCurrentUser.msearch({ + ...params, + ...frozenIndicesParams, + } as Msearch); + break; + case 'fieldCaps': + apiResult = elasticsearch.client.asCurrentUser.fieldCaps({ + ...params, + ...frozenIndicesParams, + }); + break; + case 'indices.existsAlias': + apiResult = elasticsearch.client.asCurrentUser.indices.existsAlias({ + ...params, + ...frozenIndicesParams, + } as IndicesExistsAlias); + break; + case 'indices.getAlias': + apiResult = elasticsearch.client.asCurrentUser.indices.getAlias({ + ...params, + ...frozenIndicesParams, + }); + break; + case 'indices.get': + apiResult = elasticsearch.client.asCurrentUser.indices.get({ + ...params, + ...frozenIndicesParams, + } as IndicesGet); + break; + case 'transport.request': + apiResult = elasticsearch.client.asCurrentUser.transport.request({ + ...params, + ...frozenIndicesParams, + } as TransportRequestParams); + break; + case 'ml.getBuckets': + apiResult = elasticsearch.client.asCurrentUser.ml.getBuckets({ + ...params, + ...frozenIndicesParams, + } as MlGetBuckets); + break; + } + return apiResult ? (await apiResult).body : undefined; } public getIndexPatternsService( diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts index 6b6cf5f1d563c..8b7940271d0a0 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/evaluate_condition.ts @@ -7,6 +7,7 @@ import { mapValues, last, first } from 'lodash'; import moment from 'moment'; +import { ElasticsearchClient } from 'kibana/server'; import { SnapshotCustomMetricInput } from '../../../../common/http_api/snapshot_api'; import { isTooManyBucketsPreviewException, @@ -17,7 +18,6 @@ import { CallWithRequestParams, } from '../../adapters/framework/adapter_types'; import { Comparator, InventoryMetricConditions } from './types'; -import { AlertServices } from '../../../../../alerting/server'; import { InventoryItemType, SnapshotMetricType } from '../../../../common/inventory_models/types'; import { InfraTimerangeInput, SnapshotRequest } from '../../../../common/http_api/snapshot_api'; import { InfraSource } from '../../sources'; @@ -36,7 +36,7 @@ export const evaluateCondition = async ( condition: InventoryMetricConditions, nodeType: InventoryItemType, source: InfraSource, - callCluster: AlertServices['callCluster'], + esClient: ElasticsearchClient, filterQuery?: string, lookbackSize?: number ): Promise> => { @@ -53,7 +53,7 @@ export const evaluateCondition = async ( } const currentValues = await getData( - callCluster, + esClient, nodeType, metric, timerange, @@ -96,7 +96,7 @@ const getCurrentValue: (value: any) => number = (value) => { type DataValue = number | null | Array; const getData = async ( - callCluster: AlertServices['callCluster'], + esClient: ElasticsearchClient, nodeType: InventoryItemType, metric: SnapshotMetricType, timerange: InfraTimerangeInput, @@ -104,9 +104,10 @@ const getData = async ( filterQuery?: string, customMetric?: SnapshotCustomMetricInput ) => { - const client = ( + const client = async ( options: CallWithRequestParams - ): Promise> => callCluster('search', options); + ): Promise> => + (await esClient.search(options as any)).body as InfraDatabaseSearchResponse; const metrics = [ metric === 'custom' ? (customMetric as SnapshotCustomMetricInput) : { type: metric }, diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts index f4fadd09efdf5..632ba9cd6f282 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts @@ -69,7 +69,15 @@ export const createInventoryMetricThresholdExecutor = (libs: InfraBackendLibs) = ); const results = await Promise.all( - criteria.map((c) => evaluateCondition(c, nodeType, source, services.callCluster, filterQuery)) + criteria.map((c) => + evaluateCondition( + c, + nodeType, + source, + services.scopedClusterClient.asCurrentUser, + filterQuery + ) + ) ); const inventoryItems = Object.keys(first(results)!); diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/preview_inventory_metric_threshold_alert.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/preview_inventory_metric_threshold_alert.ts index 6f3299a2cc126..472f9d408694c 100644 --- a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/preview_inventory_metric_threshold_alert.ts +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/preview_inventory_metric_threshold_alert.ts @@ -13,7 +13,7 @@ import { TOO_MANY_BUCKETS_PREVIEW_EXCEPTION, isTooManyBucketsPreviewException, } from '../../../../common/alerting/metrics'; -import { ILegacyScopedClusterClient } from '../../../../../../../src/core/server'; +import { ElasticsearchClient } from '../../../../../../../src/core/server'; import { InfraSource } from '../../../../common/http_api/source_api'; import { getIntervalInSeconds } from '../../../utils/get_interval_in_seconds'; import { InventoryItemType } from '../../../../common/inventory_models/types'; @@ -27,7 +27,7 @@ interface InventoryMetricThresholdParams { } interface PreviewInventoryMetricThresholdAlertParams { - callCluster: ILegacyScopedClusterClient['callAsCurrentUser']; + esClient: ElasticsearchClient; params: InventoryMetricThresholdParams; source: InfraSource; lookback: Unit; @@ -40,7 +40,7 @@ interface PreviewInventoryMetricThresholdAlertParams { export const previewInventoryMetricThresholdAlert: ( params: PreviewInventoryMetricThresholdAlertParams ) => Promise = async ({ - callCluster, + esClient, params, source, lookback, @@ -68,7 +68,7 @@ export const previewInventoryMetricThresholdAlert: ( try { const results = await Promise.all( criteria.map((c) => - evaluateCondition(c, nodeType, source, callCluster, filterQuery, lookbackSize) + evaluateCondition(c, nodeType, source, esClient, filterQuery, lookbackSize) ) ); diff --git a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts index 565dfa6d6d2aa..0dff7e1070971 100644 --- a/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/log_threshold/log_threshold_executor.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { ElasticsearchClient } from 'kibana/server'; import { AlertExecutorOptions, AlertServices, @@ -67,7 +68,7 @@ const checkValueAgainstComparatorMap: { export const createLogThresholdExecutor = (libs: InfraBackendLibs) => async function ({ services, params }: LogThresholdAlertExecutorOptions) { - const { alertInstanceFactory, savedObjectsClient, callCluster } = services; + const { alertInstanceFactory, savedObjectsClient, scopedClusterClient } = services; const { sources } = libs; const sourceConfiguration = await sources.getSourceConfiguration(savedObjectsClient, 'default'); @@ -82,7 +83,7 @@ export const createLogThresholdExecutor = (libs: InfraBackendLibs) => validatedParams, timestampField, indexPattern, - callCluster, + scopedClusterClient.asCurrentUser, alertInstanceFactory ); } else { @@ -90,7 +91,7 @@ export const createLogThresholdExecutor = (libs: InfraBackendLibs) => validatedParams, timestampField, indexPattern, - callCluster, + scopedClusterClient.asCurrentUser, alertInstanceFactory ); } @@ -103,7 +104,7 @@ async function executeAlert( alertParams: CountAlertParams, timestampField: string, indexPattern: string, - callCluster: LogThresholdAlertServices['callCluster'], + esClient: ElasticsearchClient, alertInstanceFactory: LogThresholdAlertServices['alertInstanceFactory'] ) { const query = getESQuery(alertParams, timestampField, indexPattern); @@ -114,14 +115,14 @@ async function executeAlert( if (hasGroupBy(alertParams)) { processGroupByResults( - await getGroupedResults(query, callCluster), + await getGroupedResults(query, esClient), alertParams, alertInstanceFactory, updateAlertInstance ); } else { processUngroupedResults( - await getUngroupedResults(query, callCluster), + await getUngroupedResults(query, esClient), alertParams, alertInstanceFactory, updateAlertInstance @@ -133,7 +134,7 @@ async function executeRatioAlert( alertParams: RatioAlertParams, timestampField: string, indexPattern: string, - callCluster: LogThresholdAlertServices['callCluster'], + esClient: ElasticsearchClient, alertInstanceFactory: LogThresholdAlertServices['alertInstanceFactory'] ) { // Ratio alert params are separated out into two standard sets of alert params @@ -155,8 +156,8 @@ async function executeRatioAlert( } if (hasGroupBy(alertParams)) { - const numeratorGroupedResults = await getGroupedResults(numeratorQuery, callCluster); - const denominatorGroupedResults = await getGroupedResults(denominatorQuery, callCluster); + const numeratorGroupedResults = await getGroupedResults(numeratorQuery, esClient); + const denominatorGroupedResults = await getGroupedResults(denominatorQuery, esClient); processGroupByRatioResults( numeratorGroupedResults, denominatorGroupedResults, @@ -165,8 +166,8 @@ async function executeRatioAlert( updateAlertInstance ); } else { - const numeratorUngroupedResults = await getUngroupedResults(numeratorQuery, callCluster); - const denominatorUngroupedResults = await getUngroupedResults(denominatorQuery, callCluster); + const numeratorUngroupedResults = await getUngroupedResults(numeratorQuery, esClient); + const denominatorUngroupedResults = await getUngroupedResults(denominatorQuery, esClient); processUngroupedRatioResults( numeratorUngroupedResults, denominatorUngroupedResults, @@ -605,17 +606,11 @@ const getQueryMappingForComparator = (comparator: Comparator) => { return queryMappings[comparator]; }; -const getUngroupedResults = async ( - query: object, - callCluster: LogThresholdAlertServices['callCluster'] -) => { - return decodeOrThrow(UngroupedSearchQueryResponseRT)(await callCluster('search', query)); +const getUngroupedResults = async (query: object, esClient: ElasticsearchClient) => { + return decodeOrThrow(UngroupedSearchQueryResponseRT)((await esClient.search(query)).body); }; -const getGroupedResults = async ( - query: object, - callCluster: LogThresholdAlertServices['callCluster'] -) => { +const getGroupedResults = async (query: object, esClient: ElasticsearchClient) => { let compositeGroupBuckets: GroupedSearchQueryResponse['aggregations']['groups']['buckets'] = []; let lastAfterKey: GroupedSearchQueryResponse['aggregations']['groups']['after_key'] | undefined; @@ -623,7 +618,7 @@ const getGroupedResults = async ( const queryWithAfterKey: any = { ...query }; queryWithAfterKey.body.aggregations.groups.composite.after = lastAfterKey; const groupResponse: GroupedSearchQueryResponse = decodeOrThrow(GroupedSearchQueryResponseRT)( - await callCluster('search', queryWithAfterKey) + (await esClient.search(queryWithAfterKey)).body ); compositeGroupBuckets = [ ...compositeGroupBuckets, diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts index 3f6bb075c8f92..b7d3dbb1f7adb 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/lib/evaluate_alert.ts @@ -6,6 +6,7 @@ */ import { mapValues, first, last, isNaN } from 'lodash'; +import { ElasticsearchClient } from 'kibana/server'; import { isTooManyBucketsPreviewException, TOO_MANY_BUCKETS_PREVIEW_EXCEPTION, @@ -13,7 +14,6 @@ import { import { InfraSource } from '../../../../../common/http_api/source_api'; import { InfraDatabaseSearchResponse } from '../../../adapters/framework/adapter_types'; import { createAfterKeyHandler } from '../../../../utils/create_afterkey_handler'; -import { AlertServices } from '../../../../../../alerting/server'; import { getAllCompositeData } from '../../../../utils/get_all_composite_data'; import { DOCUMENT_COUNT_I18N } from '../../common/messages'; import { UNGROUPED_FACTORY_KEY } from '../../common/utils'; @@ -43,7 +43,7 @@ export interface EvaluatedAlertParams { } export const evaluateAlert = ( - callCluster: AlertServices['callCluster'], + esClient: ElasticsearchClient, params: Params, config: InfraSource['configuration'], timeframe?: { start: number; end: number } @@ -52,7 +52,7 @@ export const evaluateAlert = { const currentValues = await getMetric( - callCluster, + esClient, criterion, config.metricAlias, config.fields.timestamp, @@ -91,7 +91,7 @@ export const evaluateAlert = Promise> = async function ( - callCluster, + esClient, params, index, timefield, @@ -127,7 +127,7 @@ const getMetric: ( (response) => response.aggregations?.groupings?.after_key ); const compositeBuckets = (await getAllCompositeData( - (body) => callCluster('search', { body, index }), + (body) => esClient.search({ body, index }), searchBody, bucketSelector, afterKeyHandler @@ -142,7 +142,7 @@ const getMetric: ( {} ); } - const result = await callCluster('search', { + const { body: result } = await esClient.search({ body: searchBody, index, }); diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index 8d052f725fe20..9086d6436c2a2 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -16,6 +16,8 @@ import { } from '../../../../../alerting/server/mocks'; import { InfraSources } from '../../sources'; import { MetricThresholdAlertExecutorOptions } from './register_metric_threshold_alert_type'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; interface AlertTestInstance { instance: AlertInstanceMock; @@ -439,26 +441,36 @@ const mockLibs: any = { const executor = createMetricThresholdExecutor(mockLibs); const services: AlertServicesMock = alertsMock.createAlertServices(); -services.callCluster.mockImplementation(async (_: string, { body, index }: any) => { - if (index === 'alternatebeat-*') return mocks.changedSourceIdResponse; - const metric = body.query.bool.filter[1]?.exists.field; - if (body.aggs.groupings) { - if (body.aggs.groupings.composite.after) { - return mocks.compositeEndResponse; +services.scopedClusterClient.asCurrentUser.search.mockImplementation((params?: any): any => { + if (params.index === 'alternatebeat-*') return mocks.changedSourceIdResponse; + const metric = params?.body.query.bool.filter[1]?.exists.field; + if (params?.body.aggs.groupings) { + if (params?.body.aggs.groupings.composite.after) { + return elasticsearchClientMock.createSuccessTransportRequestPromise( + mocks.compositeEndResponse + ); } if (metric === 'test.metric.2') { - return mocks.alternateCompositeResponse; + return elasticsearchClientMock.createSuccessTransportRequestPromise( + mocks.alternateCompositeResponse + ); } - return mocks.basicCompositeResponse; + return elasticsearchClientMock.createSuccessTransportRequestPromise( + mocks.basicCompositeResponse + ); } if (metric === 'test.metric.2') { - return mocks.alternateMetricResponse; + return elasticsearchClientMock.createSuccessTransportRequestPromise( + mocks.alternateMetricResponse + ); } else if (metric === 'test.metric.3') { - return body.aggs.aggregatedIntervals.aggregations.aggregatedValue_max - ? mocks.emptyRateResponse - : mocks.emptyMetricResponse; + return elasticsearchClientMock.createSuccessTransportRequestPromise( + params?.body.aggs.aggregatedIntervals.aggregations.aggregatedValue_max + ? mocks.emptyRateResponse + : mocks.emptyMetricResponse + ); } - return mocks.basicMetricResponse; + return elasticsearchClientMock.createSuccessTransportRequestPromise(mocks.basicMetricResponse); }); services.savedObjectsClient.get.mockImplementation(async (type: string, sourceId: string) => { if (sourceId === 'alternate') diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts index 934d6cc4293ad..190d8e028fe0d 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts @@ -44,7 +44,7 @@ export const createMetricThresholdExecutor = ( ); const config = source.configuration; const alertResults = await evaluateAlert( - services.callCluster, + services.scopedClusterClient.asCurrentUser, params as EvaluatedAlertParams, config ); diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.test.ts index 551116ddac091..49cb8d70f6020 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.test.ts @@ -9,6 +9,8 @@ import * as mocks from './test_mocks'; import { Comparator, Aggregators, MetricExpressionParams } from './types'; import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mocks'; import { previewMetricThresholdAlert } from './preview_metric_threshold_alert'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; describe('Previewing the metric threshold alert type', () => { describe('querying the entire infrastructure', () => { @@ -163,21 +165,32 @@ describe('Previewing the metric threshold alert type', () => { }); const services: AlertServicesMock = alertsMock.createAlertServices(); -services.callCluster.mockImplementation(async (_: string, { body, index }: any) => { - const metric = body.query.bool.filter[1]?.exists.field; - if (body.aggs.groupings) { - if (body.aggs.groupings.composite.after) { - return mocks.compositeEndResponse; + +services.scopedClusterClient.asCurrentUser.search.mockImplementation((params?: any): any => { + const metric = params?.body.query.bool.filter[1]?.exists.field; + if (params?.body.aggs.groupings) { + if (params?.body.aggs.groupings.composite.after) { + return elasticsearchClientMock.createSuccessTransportRequestPromise( + mocks.compositeEndResponse + ); } - return mocks.basicCompositePreviewResponse; + return elasticsearchClientMock.createSuccessTransportRequestPromise( + mocks.basicCompositePreviewResponse + ); } if (metric === 'test.metric.2') { - return mocks.alternateMetricPreviewResponse; + return elasticsearchClientMock.createSuccessTransportRequestPromise( + mocks.alternateMetricPreviewResponse + ); } if (metric === 'test.metric.3') { - return mocks.repeatingMetricPreviewResponse; + return elasticsearchClientMock.createSuccessTransportRequestPromise( + mocks.repeatingMetricPreviewResponse + ); } - return mocks.basicMetricPreviewResponse; + return elasticsearchClientMock.createSuccessTransportRequestPromise( + mocks.basicMetricPreviewResponse + ); }); const baseCriterion = { @@ -197,7 +210,7 @@ const config = { } as any; const baseParams = { - callCluster: services.callCluster, + esClient: services.scopedClusterClient.asCurrentUser, params: { criteria: [baseCriterion], groupBy: undefined, diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.ts index fe2a88d89bf4a..064804b661b74 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/preview_metric_threshold_alert.ts @@ -11,7 +11,7 @@ import { TOO_MANY_BUCKETS_PREVIEW_EXCEPTION, isTooManyBucketsPreviewException, } from '../../../../common/alerting/metrics'; -import { ILegacyScopedClusterClient } from '../../../../../../../src/core/server'; +import { ElasticsearchClient } from '../../../../../../../src/core/server'; import { InfraSource } from '../../../../common/http_api/source_api'; import { getIntervalInSeconds } from '../../../utils/get_interval_in_seconds'; import { PreviewResult } from '../common/types'; @@ -21,7 +21,7 @@ import { evaluateAlert } from './lib/evaluate_alert'; const MAX_ITERATIONS = 50; interface PreviewMetricThresholdAlertParams { - callCluster: ILegacyScopedClusterClient['callAsCurrentUser']; + esClient: ElasticsearchClient; params: { criteria: MetricExpressionParams[]; groupBy: string | undefined | string[]; @@ -43,7 +43,7 @@ export const previewMetricThresholdAlert: ( precalculatedNumberOfGroups?: number ) => Promise = async ( { - callCluster, + esClient, params, config, lookback, @@ -79,7 +79,7 @@ export const previewMetricThresholdAlert: ( // Get a date histogram using the bucket interval and the lookback interval try { - const alertResults = await evaluateAlert(callCluster, params, config, timeframe); + const alertResults = await evaluateAlert(esClient, params, config, timeframe); const groups = Object.keys(first(alertResults)!); // Now determine how to interpolate this histogram based on the alert interval @@ -174,7 +174,7 @@ export const previewMetricThresholdAlert: ( // If there's too much data on the first request, recursively slice the lookback interval // until all the data can be retrieved const basePreviewParams = { - callCluster, + esClient, params, config, lookback, @@ -187,7 +187,7 @@ export const previewMetricThresholdAlert: ( // If this is still the first iteration, try to get the number of groups in order to // calculate max buckets. If this fails, just estimate based on 1 group const currentAlertResults = !precalculatedNumberOfGroups - ? await evaluateAlert(callCluster, params, config) + ? await evaluateAlert(esClient, params, config) : []; const numberOfGroups = precalculatedNumberOfGroups ?? Math.max(Object.keys(first(currentAlertResults)!).length, 1); diff --git a/x-pack/plugins/infra/server/routes/alerting/preview.ts b/x-pack/plugins/infra/server/routes/alerting/preview.ts index d1807583acd39..6622df1a8333a 100644 --- a/x-pack/plugins/infra/server/routes/alerting/preview.ts +++ b/x-pack/plugins/infra/server/routes/alerting/preview.ts @@ -26,7 +26,6 @@ import { InfraBackendLibs } from '../../lib/infra_types'; import { assertHasInfraMlPlugins } from '../../utils/request_context'; export const initAlertPreviewRoute = ({ framework, sources }: InfraBackendLibs) => { - const { callWithRequest } = framework; framework.registerRoute( { method: 'post', @@ -46,9 +45,7 @@ export const initAlertPreviewRoute = ({ framework, sources }: InfraBackendLibs) alertNotifyWhen, } = request.body; - const callCluster = (endpoint: string, opts: Record) => { - return callWithRequest(requestContext, endpoint, opts); - }; + const esClient = requestContext.core.elasticsearch.client.asCurrentUser; const source = await sources.getSourceConfiguration( requestContext.core.savedObjects.client, @@ -64,7 +61,7 @@ export const initAlertPreviewRoute = ({ framework, sources }: InfraBackendLibs) filterQuery, } = request.body as MetricThresholdAlertPreviewRequestParams; const previewResult = await previewMetricThresholdAlert({ - callCluster, + esClient, params: { criteria, filterQuery, groupBy }, lookback, config: source.configuration, @@ -86,7 +83,7 @@ export const initAlertPreviewRoute = ({ framework, sources }: InfraBackendLibs) filterQuery, } = request.body as InventoryAlertPreviewRequestParams; const previewResult = await previewInventoryMetricThresholdAlert({ - callCluster, + esClient, params: { criteria, filterQuery, nodeType }, lookback, source, diff --git a/x-pack/plugins/infra/server/utils/get_all_composite_data.ts b/x-pack/plugins/infra/server/utils/get_all_composite_data.ts index fbe8a36f5038c..df97c91aacd04 100644 --- a/x-pack/plugins/infra/server/utils/get_all_composite_data.ts +++ b/x-pack/plugins/infra/server/utils/get_all_composite_data.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { ApiResponse } from '@elastic/elasticsearch/lib/Transport'; import { InfraDatabaseSearchResponse } from '../lib/adapters/framework'; export const getAllCompositeData = async < @@ -12,13 +13,15 @@ export const getAllCompositeData = async < Bucket = {}, Options extends object = {} >( - callCluster: (options: Options) => Promise>, + esClientSearch: ( + options: Options + ) => Promise>>, options: Options, bucketSelector: (response: InfraDatabaseSearchResponse<{}, Aggregation>) => Bucket[], onAfterKey: (options: Options, response: InfraDatabaseSearchResponse<{}, Aggregation>) => Options, previousBuckets: Bucket[] = [] ): Promise => { - const response = await callCluster(options); + const { body: response } = await esClientSearch(options); // Nothing available, return the previous buckets. if (response.hits.total.value === 0) { @@ -40,7 +43,7 @@ export const getAllCompositeData = async < // There is possibly more data, concat previous and current buckets and call ourselves recursively. const newOptions = onAfterKey(options, response); return getAllCompositeData( - callCluster, + esClientSearch, newOptions, bucketSelector, onAfterKey, diff --git a/x-pack/plugins/lists/server/plugin.ts b/x-pack/plugins/lists/server/plugin.ts index b79d6a0b89a57..004677852d020 100644 --- a/x-pack/plugins/lists/server/plugin.ts +++ b/x-pack/plugins/lists/server/plugin.ts @@ -58,10 +58,10 @@ export class ListPlugin user, }); }, - getListClient: (callCluster, spaceId, user): ListClient => { + getListClient: (esClient, spaceId, user): ListClient => { return new ListClient({ - callCluster, config, + esClient, spaceId, user, }); @@ -86,9 +86,7 @@ export class ListPlugin core: { savedObjects: { client: savedObjectsClient }, elasticsearch: { - legacy: { - client: { callAsCurrentUser: callCluster }, - }, + client: { asCurrentUser: esClient }, }, }, } = context; @@ -105,8 +103,8 @@ export class ListPlugin }), getListClient: (): ListClient => new ListClient({ - callCluster, config, + esClient, spaceId, user, }), diff --git a/x-pack/plugins/lists/server/services/items/create_list_item.mock.ts b/x-pack/plugins/lists/server/services/items/create_list_item.mock.ts index fba978d80d0bf..31befdc2122d3 100644 --- a/x-pack/plugins/lists/server/services/items/create_list_item.mock.ts +++ b/x-pack/plugins/lists/server/services/items/create_list_item.mock.ts @@ -5,7 +5,9 @@ * 2.0. */ -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { CreateListItemOptions } from '../items'; import { DATE_NOW, @@ -19,9 +21,9 @@ import { } from '../../../common/constants.mock'; export const getCreateListItemOptionsMock = (): CreateListItemOptions => ({ - callCluster: getCallClusterMock(), dateNow: DATE_NOW, deserializer: undefined, + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, id: LIST_ITEM_ID, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, diff --git a/x-pack/plugins/lists/server/services/items/create_list_item.test.ts b/x-pack/plugins/lists/server/services/items/create_list_item.test.ts index cced16b88433e..a13163d8f774a 100644 --- a/x-pack/plugins/lists/server/services/items/create_list_item.test.ts +++ b/x-pack/plugins/lists/server/services/items/create_list_item.test.ts @@ -5,6 +5,9 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { getListItemResponseMock } from '../../../common/schemas/response/list_item_schema.mock'; import { getIndexESListItemMock } from '../../../common/schemas/elastic_query/index_es_list_item_schema.mock'; import { LIST_ITEM_ID, LIST_ITEM_INDEX } from '../../../common/constants.mock'; @@ -23,13 +26,17 @@ describe('crete_list_item', () => { test('it returns a list item as expected with the id changed out for the elastic id', async () => { const options = getCreateListItemOptionsMock(); - const listItem = await createListItem(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.index.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _id: 'elastic-id-123' }) + ); + const listItem = await createListItem({ ...options, esClient }); const expected = getListItemResponseMock(); expected.id = 'elastic-id-123'; expect(listItem).toEqual(expected); }); - test('It calls "callCluster" with body, index, and listIndex', async () => { + test('It calls "esClient" with body, index, and listIndex', async () => { const options = getCreateListItemOptionsMock(); await createListItem(options); const body = getIndexESListItemMock(); @@ -39,13 +46,17 @@ describe('crete_list_item', () => { index: LIST_ITEM_INDEX, refresh: 'wait_for', }; - expect(options.callCluster).toBeCalledWith('index', expected); + expect(options.esClient.index).toBeCalledWith(expected); }); test('It returns an auto-generated id if id is sent in undefined', async () => { const options = getCreateListItemOptionsMock(); options.id = undefined; - const list = await createListItem(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.index.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _id: 'elastic-id-123' }) + ); + const list = await createListItem({ ...options, esClient }); const expected = getListItemResponseMock(); expected.id = 'elastic-id-123'; expect(list).toEqual(expected); diff --git a/x-pack/plugins/lists/server/services/items/create_list_item.ts b/x-pack/plugins/lists/server/services/items/create_list_item.ts index bac2958857124..a5369bbfe7ca4 100644 --- a/x-pack/plugins/lists/server/services/items/create_list_item.ts +++ b/x-pack/plugins/lists/server/services/items/create_list_item.ts @@ -7,7 +7,7 @@ import uuid from 'uuid'; import { CreateDocumentResponse } from 'elasticsearch'; -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { DeserializerOrUndefined, @@ -28,7 +28,7 @@ export interface CreateListItemOptions { listId: string; type: Type; value: string; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listItemIndex: string; user: string; meta: MetaOrUndefined; @@ -43,7 +43,7 @@ export const createListItem = async ({ listId, type, value, - callCluster, + esClient, listItemIndex, user, meta, @@ -69,7 +69,7 @@ export const createListItem = async ({ ...baseBody, ...elasticQuery, }; - const response = await callCluster('index', { + const { body: response } = await esClient.index({ body, id, index: listItemIndex, diff --git a/x-pack/plugins/lists/server/services/items/create_list_items_bulk.mock.ts b/x-pack/plugins/lists/server/services/items/create_list_items_bulk.mock.ts index d6a752df38efc..d2ceb32b91951 100644 --- a/x-pack/plugins/lists/server/services/items/create_list_items_bulk.mock.ts +++ b/x-pack/plugins/lists/server/services/items/create_list_items_bulk.mock.ts @@ -5,7 +5,9 @@ * 2.0. */ -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { CreateListItemsBulkOptions } from '../items'; import { DATE_NOW, @@ -20,9 +22,9 @@ import { } from '../../../common/constants.mock'; export const getCreateListItemBulkOptionsMock = (): CreateListItemsBulkOptions => ({ - callCluster: getCallClusterMock(), dateNow: DATE_NOW, deserializer: undefined, + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, meta: META, diff --git a/x-pack/plugins/lists/server/services/items/create_list_items_bulk.test.ts b/x-pack/plugins/lists/server/services/items/create_list_items_bulk.test.ts index 38e22e9b19ef6..f9f9728798a0b 100644 --- a/x-pack/plugins/lists/server/services/items/create_list_items_bulk.test.ts +++ b/x-pack/plugins/lists/server/services/items/create_list_items_bulk.test.ts @@ -20,13 +20,13 @@ describe('crete_list_item_bulk', () => { jest.clearAllMocks(); }); - test('It calls "callCluster" with body, index, and the bulk items', async () => { + test('It calls "esClient" with body, index, and the bulk items', async () => { const options = getCreateListItemBulkOptionsMock(); await createListItemsBulk(options); const firstRecord = getIndexESListItemMock(); const secondRecord = getIndexESListItemMock(VALUE_2); [firstRecord.tie_breaker_id, secondRecord.tie_breaker_id] = TIE_BREAKERS; - expect(options.callCluster).toBeCalledWith('bulk', { + expect(options.esClient.bulk).toBeCalledWith({ body: [ { create: { _index: LIST_ITEM_INDEX } }, firstRecord, @@ -41,7 +41,7 @@ describe('crete_list_item_bulk', () => { test('It should not call the dataClient when the values are empty', async () => { const options = getCreateListItemBulkOptionsMock(); options.value = []; - expect(options.callCluster).not.toBeCalled(); + expect(options.esClient.bulk).not.toBeCalled(); }); test('It should skip over a value if it is not able to add that item because it is not parsable such as an ip_range with a serializer that only matches one ip', async () => { @@ -52,7 +52,7 @@ describe('crete_list_item_bulk', () => { value: ['127.0.0.1', '127.0.0.2'], }; await createListItemsBulk(options); - expect(options.callCluster).toBeCalledWith('bulk', { + expect(options.esClient.bulk).toBeCalledWith({ body: [ { create: { _index: LIST_ITEM_INDEX } }, { diff --git a/x-pack/plugins/lists/server/services/items/create_list_items_bulk.ts b/x-pack/plugins/lists/server/services/items/create_list_items_bulk.ts index 0f8b5b7a08595..86d8d9a698b1f 100644 --- a/x-pack/plugins/lists/server/services/items/create_list_items_bulk.ts +++ b/x-pack/plugins/lists/server/services/items/create_list_items_bulk.ts @@ -6,7 +6,7 @@ */ import uuid from 'uuid'; -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { transformListItemToElasticQuery } from '../utils'; import { @@ -24,7 +24,7 @@ export interface CreateListItemsBulkOptions { listId: string; type: Type; value: string[]; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listItemIndex: string; user: string; meta: MetaOrUndefined; @@ -38,7 +38,7 @@ export const createListItemsBulk = async ({ deserializer, serializer, value, - callCluster, + esClient, listItemIndex, user, meta, @@ -82,7 +82,7 @@ export const createListItemsBulk = async ({ [] ); try { - await callCluster('bulk', { + await esClient.bulk({ body, index: listItemIndex, refresh: 'wait_for', diff --git a/x-pack/plugins/lists/server/services/items/delete_list_item.mock.ts b/x-pack/plugins/lists/server/services/items/delete_list_item.mock.ts index 9755afcd5422f..89331d02dc3ff 100644 --- a/x-pack/plugins/lists/server/services/items/delete_list_item.mock.ts +++ b/x-pack/plugins/lists/server/services/items/delete_list_item.mock.ts @@ -5,12 +5,14 @@ * 2.0. */ -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { DeleteListItemOptions } from '../items'; import { LIST_ITEM_ID, LIST_ITEM_INDEX } from '../../../common/constants.mock'; export const getDeleteListItemOptionsMock = (): DeleteListItemOptions => ({ - callCluster: getCallClusterMock(), + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, id: LIST_ITEM_ID, listItemIndex: LIST_ITEM_INDEX, }); diff --git a/x-pack/plugins/lists/server/services/items/delete_list_item.test.ts b/x-pack/plugins/lists/server/services/items/delete_list_item.test.ts index 364b575587d42..de5b6540eee40 100644 --- a/x-pack/plugins/lists/server/services/items/delete_list_item.test.ts +++ b/x-pack/plugins/lists/server/services/items/delete_list_item.test.ts @@ -50,6 +50,6 @@ describe('delete_list_item', () => { index: LIST_ITEM_INDEX, refresh: 'wait_for', }; - expect(options.callCluster).toBeCalledWith('delete', deleteQuery); + expect(options.esClient.delete).toBeCalledWith(deleteQuery); }); }); diff --git a/x-pack/plugins/lists/server/services/items/delete_list_item.ts b/x-pack/plugins/lists/server/services/items/delete_list_item.ts index 8f1728c5b4a70..f2e9949c82c3e 100644 --- a/x-pack/plugins/lists/server/services/items/delete_list_item.ts +++ b/x-pack/plugins/lists/server/services/items/delete_list_item.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { Id, ListItemSchema } from '../../../common/schemas'; @@ -13,20 +13,20 @@ import { getListItem } from '.'; export interface DeleteListItemOptions { id: Id; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listItemIndex: string; } export const deleteListItem = async ({ id, - callCluster, + esClient, listItemIndex, }: DeleteListItemOptions): Promise => { - const listItem = await getListItem({ callCluster, id, listItemIndex }); + const listItem = await getListItem({ esClient, id, listItemIndex }); if (listItem == null) { return null; } else { - await callCluster('delete', { + await esClient.delete({ id, index: listItemIndex, refresh: 'wait_for', diff --git a/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.mock.ts b/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.mock.ts index ef9cc0b46c0c2..54bfe3bae0811 100644 --- a/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.mock.ts +++ b/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.mock.ts @@ -5,12 +5,14 @@ * 2.0. */ -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { DeleteListItemByValueOptions } from '../items'; import { LIST_ID, LIST_ITEM_INDEX, TYPE, VALUE } from '../../../common/constants.mock'; export const getDeleteListItemByValueOptionsMock = (): DeleteListItemByValueOptions => ({ - callCluster: getCallClusterMock(), + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, type: TYPE, diff --git a/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.test.ts b/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.test.ts index c2c7fae942ac3..2755ff8e7aba6 100644 --- a/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.test.ts +++ b/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.test.ts @@ -61,8 +61,8 @@ describe('delete_list_item_by_value', () => { }, }, index: '.items', - refresh: 'wait_for', + refresh: false, }; - expect(options.callCluster).toBeCalledWith('deleteByQuery', deleteByQuery); + expect(options.esClient.deleteByQuery).toBeCalledWith(deleteByQuery); }); }); diff --git a/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.ts b/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.ts index bf02d30b324b8..1c7ac3afb3ee3 100644 --- a/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.ts +++ b/x-pack/plugins/lists/server/services/items/delete_list_item_by_value.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { ListItemArraySchema, Type } from '../../../common/schemas'; import { getQueryFilterFromTypeValue } from '../utils'; @@ -16,7 +16,7 @@ export interface DeleteListItemByValueOptions { listId: string; type: Type; value: string; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listItemIndex: string; } @@ -24,11 +24,11 @@ export const deleteListItemByValue = async ({ listId, value, type, - callCluster, + esClient, listItemIndex, }: DeleteListItemByValueOptions): Promise => { const listItems = await getListItemByValues({ - callCluster, + esClient, listId, listItemIndex, type, @@ -40,7 +40,7 @@ export const deleteListItemByValue = async ({ type, value: values, }); - await callCluster('deleteByQuery', { + await esClient.deleteByQuery({ body: { query: { bool: { @@ -49,7 +49,7 @@ export const deleteListItemByValue = async ({ }, }, index: listItemIndex, - refresh: 'wait_for', + refresh: false, }); return listItems; }; diff --git a/x-pack/plugins/lists/server/services/items/find_list_item.mock.ts b/x-pack/plugins/lists/server/services/items/find_list_item.mock.ts index 81b9375bb7c4a..4bf62982b2a9f 100644 --- a/x-pack/plugins/lists/server/services/items/find_list_item.mock.ts +++ b/x-pack/plugins/lists/server/services/items/find_list_item.mock.ts @@ -6,11 +6,10 @@ */ import { Client } from 'elasticsearch'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; -import { getSearchListMock } from '../../../common/schemas/elastic_response/search_es_list_schema.mock'; import { getShardMock } from '../../../common/get_shard.mock'; -import { getSearchListItemMock } from '../../../common/schemas/elastic_response/search_es_list_item_schema.mock'; -import { getCallClusterMockMultiTimes } from '../../../common/get_call_cluster.mock'; import { LIST_ID, LIST_INDEX, LIST_ITEM_INDEX } from '../../../common/constants.mock'; import { FindListItemOptions } from './find_list_item'; @@ -23,14 +22,9 @@ export const getFindCount = (): ReturnType => { }; export const getFindListItemOptionsMock = (): FindListItemOptions => { - const callCluster = getCallClusterMockMultiTimes([ - getSearchListMock(), - getFindCount(), - getSearchListItemMock(), - ]); return { - callCluster, currentIndexPosition: 0, + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, filter: '', listId: LIST_ID, listIndex: LIST_INDEX, diff --git a/x-pack/plugins/lists/server/services/items/find_list_item.test.ts b/x-pack/plugins/lists/server/services/items/find_list_item.test.ts index 4cd7e4aaef00a..29e6f2f845002 100644 --- a/x-pack/plugins/lists/server/services/items/find_list_item.test.ts +++ b/x-pack/plugins/lists/server/services/items/find_list_item.test.ts @@ -5,9 +5,12 @@ * 2.0. */ -import { getEmptySearchListMock } from '../../../common/schemas/elastic_response/search_es_list_schema.mock'; -import { getCallClusterMockMultiTimes } from '../../../common/get_call_cluster.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + +import { getShardMock } from '../../../common/get_shard.mock'; import { getFoundListItemSchemaMock } from '../../../common/schemas/response/found_list_item_schema.mock'; +import { getEmptySearchListMock } from '../../../common/schemas/elastic_response/search_es_list_schema.mock'; import { getFindListItemOptionsMock } from './find_list_item.mock'; import { findListItem } from './find_list_item'; @@ -15,15 +18,53 @@ import { findListItem } from './find_list_item'; describe('find_list_item', () => { test('should find a simple single list item', async () => { const options = getFindListItemOptionsMock(); - const item = await findListItem(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.count.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ count: 1 }) + ); + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + _scroll_id: '123', + _shards: getShardMock(), + hits: { + hits: [ + { + _id: 'some-list-item-id', + _source: { + _version: 'undefined', + created_at: '2020-04-20T15:25:31.830Z', + created_by: 'some user', + date_range: '127.0.0.1', + deserializer: undefined, + list_id: 'some-list-id', + meta: {}, + serializer: undefined, + tie_breaker_id: '6a76b69d-80df-4ab2-8c3e-85f466b06a0e', + type: 'ip', + updated_at: '2020-04-20T15:25:31.830Z', + updated_by: 'some user', + }, + }, + ], + max_score: 0, + total: 1, + }, + timed_out: false, + took: 10, + }) + ); + const item = await findListItem({ ...options, esClient }); const expected = getFoundListItemSchemaMock(); expect(item).toEqual(expected); }); test('should return null if the list is null', async () => { const options = getFindListItemOptionsMock(); - options.callCluster = getCallClusterMockMultiTimes([getEmptySearchListMock()]); - const item = await findListItem(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(getEmptySearchListMock()) + ); + const item = await findListItem({ ...options, esClient }); expect(item).toEqual(null); }); }); diff --git a/x-pack/plugins/lists/server/services/items/find_list_item.ts b/x-pack/plugins/lists/server/services/items/find_list_item.ts index e0639bc51ce7b..727c55d53e459 100644 --- a/x-pack/plugins/lists/server/services/items/find_list_item.ts +++ b/x-pack/plugins/lists/server/services/items/find_list_item.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { SearchResponse } from 'elasticsearch'; import { @@ -37,13 +37,13 @@ export interface FindListItemOptions { page: Page; sortField: SortFieldOrUndefined; sortOrder: SortOrderOrUndefined; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listIndex: string; listItemIndex: string; } export const findListItem = async ({ - callCluster, + esClient, currentIndexPosition, filter, listId, @@ -55,7 +55,7 @@ export const findListItem = async ({ listItemIndex, sortOrder, }: FindListItemOptions): Promise => { - const list = await getList({ callCluster, id: listId, listIndex }); + const list = await getList({ esClient, id: listId, listIndex }); if (list == null) { return null; } else { @@ -63,8 +63,8 @@ export const findListItem = async ({ const sortField = sortFieldWithPossibleValue === 'value' ? list.type : sortFieldWithPossibleValue; const scroll = await scrollToStartPage({ - callCluster, currentIndexPosition, + esClient, filter, hopSize: 100, index: listItemIndex, @@ -75,25 +75,25 @@ export const findListItem = async ({ sortOrder, }); - const { count } = await callCluster('count', { + const { body: respose } = await esClient.count<{ count: number }>({ body: { query, }, - ignoreUnavailable: true, + ignore_unavailable: true, index: listItemIndex, }); if (scroll.validSearchAfterFound) { - // Note: This typing of response = await callCluster> + // Note: This typing of response = await esClient> // is because when you pass in seq_no_primary_term: true it does a "fall through" type and you have // to explicitly define the type . - const response = await callCluster>('search', { + const { body: response } = await esClient.search>({ body: { query, search_after: scroll.searchAfter, sort: getSortWithTieBreaker({ sortField, sortOrder }), }, - ignoreUnavailable: true, + ignore_unavailable: true, index: listItemIndex, seq_no_primary_term: true, size: perPage, @@ -107,7 +107,7 @@ export const findListItem = async ({ data: transformElasticToListItem({ response, type: list.type }), page, per_page: perPage, - total: count, + total: respose.count, }; } else { return { @@ -115,7 +115,7 @@ export const findListItem = async ({ data: [], page, per_page: perPage, - total: count, + total: respose.count, }; } } diff --git a/x-pack/plugins/lists/server/services/items/get_list_item.test.ts b/x-pack/plugins/lists/server/services/items/get_list_item.test.ts index 34425f10ec5ad..f92031cae02ca 100644 --- a/x-pack/plugins/lists/server/services/items/get_list_item.test.ts +++ b/x-pack/plugins/lists/server/services/items/get_list_item.test.ts @@ -5,9 +5,11 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { getSearchListItemMock } from '../../../common/schemas/elastic_response/search_es_list_item_schema.mock'; import { getListItemResponseMock } from '../../../common/schemas/response/list_item_schema.mock'; -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; import { DATE_NOW, LIST_ID, @@ -30,8 +32,11 @@ describe('get_list_item', () => { test('it returns a list item as expected if the list item is found', async () => { const data = getSearchListItemMock(); - const callCluster = getCallClusterMock(data); - const list = await getListItem({ callCluster, id: LIST_ID, listItemIndex: LIST_INDEX }); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(data) + ); + const list = await getListItem({ esClient, id: LIST_ID, listItemIndex: LIST_INDEX }); const expected = getListItemResponseMock(); expect(list).toEqual(expected); }); @@ -39,8 +44,11 @@ describe('get_list_item', () => { test('it returns null if the search is empty', async () => { const data = getSearchListItemMock(); data.hits.hits = []; - const callCluster = getCallClusterMock(data); - const list = await getListItem({ callCluster, id: LIST_ID, listItemIndex: LIST_INDEX }); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(data) + ); + const list = await getListItem({ esClient, id: LIST_ID, listItemIndex: LIST_INDEX }); expect(list).toEqual(null); }); @@ -80,8 +88,11 @@ describe('get_list_item', () => { updated_at: DATE_NOW, updated_by: USER, }; - const callCluster = getCallClusterMock(data); - const list = await getListItem({ callCluster, id: LIST_ID, listItemIndex: LIST_INDEX }); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(data) + ); + const list = await getListItem({ esClient, id: LIST_ID, listItemIndex: LIST_INDEX }); expect(list).toEqual(null); }); }); diff --git a/x-pack/plugins/lists/server/services/items/get_list_item.ts b/x-pack/plugins/lists/server/services/items/get_list_item.ts index 2ccf27e0c00dc..eb05a899478a5 100644 --- a/x-pack/plugins/lists/server/services/items/get_list_item.ts +++ b/x-pack/plugins/lists/server/services/items/get_list_item.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { SearchResponse } from 'elasticsearch'; import { Id, ListItemSchema, SearchEsListItemSchema } from '../../../common/schemas'; @@ -14,19 +14,19 @@ import { findSourceType } from '../utils/find_source_type'; interface GetListItemOptions { id: Id; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listItemIndex: string; } export const getListItem = async ({ id, - callCluster, + esClient, listItemIndex, }: GetListItemOptions): Promise => { - // Note: This typing of response = await callCluster> + // Note: This typing of response = await esClient> // is because when you pass in seq_no_primary_term: true it does a "fall through" type and you have // to explicitly define the type . - const listItemES = await callCluster>('search', { + const { body: listItemES } = await esClient.search>({ body: { query: { term: { @@ -34,7 +34,7 @@ export const getListItem = async ({ }, }, }, - ignoreUnavailable: true, + ignore_unavailable: true, index: listItemIndex, seq_no_primary_term: true, }); diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_by_value.mock.ts b/x-pack/plugins/lists/server/services/items/get_list_item_by_value.mock.ts index 18e7f044bc4ca..3cd329fca3708 100644 --- a/x-pack/plugins/lists/server/services/items/get_list_item_by_value.mock.ts +++ b/x-pack/plugins/lists/server/services/items/get_list_item_by_value.mock.ts @@ -5,12 +5,14 @@ * 2.0. */ -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { GetListItemByValueOptions } from '../items'; import { LIST_ID, LIST_ITEM_INDEX, TYPE, VALUE } from '../../../common/constants.mock'; export const getListItemByValueOptionsMocks = (): GetListItemByValueOptions => ({ - callCluster: getCallClusterMock(), + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, type: TYPE, diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_by_value.ts b/x-pack/plugins/lists/server/services/items/get_list_item_by_value.ts index 8af7e3bdc4156..7d3fe81babe59 100644 --- a/x-pack/plugins/lists/server/services/items/get_list_item_by_value.ts +++ b/x-pack/plugins/lists/server/services/items/get_list_item_by_value.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { ListItemArraySchema, Type } from '../../../common/schemas'; @@ -13,7 +13,7 @@ import { getListItemByValues } from '.'; export interface GetListItemByValueOptions { listId: string; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listItemIndex: string; type: Type; value: string; @@ -21,13 +21,13 @@ export interface GetListItemByValueOptions { export const getListItemByValue = async ({ listId, - callCluster, + esClient, listItemIndex, type, value, }: GetListItemByValueOptions): Promise => getListItemByValues({ - callCluster, + esClient, listId, listItemIndex, type, diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_by_values.mock.ts b/x-pack/plugins/lists/server/services/items/get_list_item_by_values.mock.ts index 9496e175dd9a5..169934b2ee256 100644 --- a/x-pack/plugins/lists/server/services/items/get_list_item_by_values.mock.ts +++ b/x-pack/plugins/lists/server/services/items/get_list_item_by_values.mock.ts @@ -5,12 +5,14 @@ * 2.0. */ -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { GetListItemByValuesOptions } from '../items'; import { LIST_ID, LIST_ITEM_INDEX, TYPE, VALUE, VALUE_2 } from '../../../common/constants.mock'; export const getListItemByValuesOptionsMocks = (): GetListItemByValuesOptions => ({ - callCluster: getCallClusterMock(), + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, type: TYPE, diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_by_values.test.ts b/x-pack/plugins/lists/server/services/items/get_list_item_by_values.test.ts index b5db19451063b..aa22049ce6fe4 100644 --- a/x-pack/plugins/lists/server/services/items/get_list_item_by_values.test.ts +++ b/x-pack/plugins/lists/server/services/items/get_list_item_by_values.test.ts @@ -5,8 +5,10 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { getSearchListItemMock } from '../../../common/schemas/elastic_response/search_es_list_item_schema.mock'; -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; import { DATE_NOW, LIST_ID, @@ -34,9 +36,12 @@ describe('get_list_item_by_values', () => { test('Returns a an empty array if the ES query is also empty', async () => { const data = getSearchListItemMock(); data.hits.hits = []; - const callCluster = getCallClusterMock(data); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(data) + ); const listItem = await getListItemByValues({ - callCluster, + esClient, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, type: TYPE, @@ -48,9 +53,12 @@ describe('get_list_item_by_values', () => { test('Returns transformed list item if the data exists within ES', async () => { const data = getSearchListItemMock(); - const callCluster = getCallClusterMock(data); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(data) + ); const listItem = await getListItemByValues({ - callCluster, + esClient, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, type: TYPE, diff --git a/x-pack/plugins/lists/server/services/items/get_list_item_by_values.ts b/x-pack/plugins/lists/server/services/items/get_list_item_by_values.ts index 6b76f55f4ccc5..c00ee2b13426a 100644 --- a/x-pack/plugins/lists/server/services/items/get_list_item_by_values.ts +++ b/x-pack/plugins/lists/server/services/items/get_list_item_by_values.ts @@ -5,14 +5,18 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { ListItemArraySchema, SearchEsListItemSchema, Type } from '../../../common/schemas'; -import { getQueryFilterFromTypeValue, transformElasticToListItem } from '../utils'; +import { + TransformElasticToListItemOptions, + getQueryFilterFromTypeValue, + transformElasticToListItem, +} from '../utils'; export interface GetListItemByValuesOptions { listId: string; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listItemIndex: string; type: Type; value: string[]; @@ -20,12 +24,12 @@ export interface GetListItemByValuesOptions { export const getListItemByValues = async ({ listId, - callCluster, + esClient, listItemIndex, type, value, }: GetListItemByValuesOptions): Promise => { - const response = await callCluster('search', { + const { body: response } = await esClient.search({ body: { query: { bool: { @@ -33,9 +37,12 @@ export const getListItemByValues = async ({ }, }, }, - ignoreUnavailable: true, + ignore_unavailable: true, index: listItemIndex, size: 10000, // TODO: This has a limit on the number which is 10,000 the default of Elastic but we might want to provide a way to increase that number }); - return transformElasticToListItem({ response, type }); + return transformElasticToListItem(({ + response, + type, + } as unknown) as TransformElasticToListItemOptions); }; diff --git a/x-pack/plugins/lists/server/services/items/search_list_item_by_values.mock.ts b/x-pack/plugins/lists/server/services/items/search_list_item_by_values.mock.ts index 8b8a6a3041351..656b569502fbb 100644 --- a/x-pack/plugins/lists/server/services/items/search_list_item_by_values.mock.ts +++ b/x-pack/plugins/lists/server/services/items/search_list_item_by_values.mock.ts @@ -5,12 +5,14 @@ * 2.0. */ -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { SearchListItemByValuesOptions } from '../items'; import { LIST_ID, LIST_ITEM_INDEX, TYPE, VALUE, VALUE_2 } from '../../../common/constants.mock'; export const searchListItemByValuesOptionsMocks = (): SearchListItemByValuesOptions => ({ - callCluster: getCallClusterMock(), + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, type: TYPE, diff --git a/x-pack/plugins/lists/server/services/items/search_list_item_by_values.test.ts b/x-pack/plugins/lists/server/services/items/search_list_item_by_values.test.ts index d989dd6c92e3a..0d084c50b5745 100644 --- a/x-pack/plugins/lists/server/services/items/search_list_item_by_values.test.ts +++ b/x-pack/plugins/lists/server/services/items/search_list_item_by_values.test.ts @@ -5,9 +5,11 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { SearchListItemArraySchema } from '../../../common/schemas'; import { getSearchListItemMock } from '../../../common/schemas/elastic_response/search_es_list_item_schema.mock'; -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; import { LIST_ID, LIST_ITEM_INDEX, TYPE, VALUE, VALUE_2 } from '../../../common/constants.mock'; import { searchListItemByValues } from './search_list_item_by_values'; @@ -24,9 +26,12 @@ describe('search_list_item_by_values', () => { test('Returns a an empty array of items if the value is empty', async () => { const data = getSearchListItemMock(); data.hits.hits = []; - const callCluster = getCallClusterMock(data); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(data) + ); const listItem = await searchListItemByValues({ - callCluster, + esClient, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, type: TYPE, @@ -39,9 +44,12 @@ describe('search_list_item_by_values', () => { test('Returns a an empty array of items if the ES query is also empty', async () => { const data = getSearchListItemMock(); data.hits.hits = []; - const callCluster = getCallClusterMock(data); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(data) + ); const listItem = await searchListItemByValues({ - callCluster, + esClient, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, type: TYPE, @@ -57,9 +65,12 @@ describe('search_list_item_by_values', () => { test('Returns transformed list item if the data exists within ES', async () => { const data = getSearchListItemMock(); - const callCluster = getCallClusterMock(data); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(data) + ); const listItem = await searchListItemByValues({ - callCluster, + esClient, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, type: TYPE, diff --git a/x-pack/plugins/lists/server/services/items/search_list_item_by_values.ts b/x-pack/plugins/lists/server/services/items/search_list_item_by_values.ts index f15f57dfbbd07..4f8808d06e425 100644 --- a/x-pack/plugins/lists/server/services/items/search_list_item_by_values.ts +++ b/x-pack/plugins/lists/server/services/items/search_list_item_by_values.ts @@ -5,14 +5,18 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { SearchEsListItemSchema, SearchListItemArraySchema, Type } from '../../../common/schemas'; -import { getQueryFilterFromTypeValue, transformElasticNamedSearchToListItem } from '../utils'; +import { + TransformElasticMSearchToListItemOptions, + getQueryFilterFromTypeValue, + transformElasticNamedSearchToListItem, +} from '../utils'; export interface SearchListItemByValuesOptions { listId: string; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listItemIndex: string; type: Type; value: unknown[]; @@ -20,12 +24,12 @@ export interface SearchListItemByValuesOptions { export const searchListItemByValues = async ({ listId, - callCluster, + esClient, listItemIndex, type, value, }: SearchListItemByValuesOptions): Promise => { - const response = await callCluster('search', { + const { body: response } = await esClient.search({ body: { query: { bool: { @@ -33,9 +37,13 @@ export const searchListItemByValues = async ({ }, }, }, - ignoreUnavailable: true, + ignore_unavailable: true, index: listItemIndex, size: 10000, // TODO: This has a limit on the number which is 10,000 the default of Elastic but we might want to provide a way to increase that number }); - return transformElasticNamedSearchToListItem({ response, type, value }); + return transformElasticNamedSearchToListItem(({ + response, + type, + value, + } as unknown) as TransformElasticMSearchToListItemOptions); }; diff --git a/x-pack/plugins/lists/server/services/items/update_list_item.mock.ts b/x-pack/plugins/lists/server/services/items/update_list_item.mock.ts index c69f087c96a72..705e207853543 100644 --- a/x-pack/plugins/lists/server/services/items/update_list_item.mock.ts +++ b/x-pack/plugins/lists/server/services/items/update_list_item.mock.ts @@ -5,7 +5,9 @@ * 2.0. */ -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { UpdateListItemOptions } from '../items'; import { DATE_NOW, @@ -18,8 +20,8 @@ import { export const getUpdateListItemOptionsMock = (): UpdateListItemOptions => ({ _version: undefined, - callCluster: getCallClusterMock(), dateNow: DATE_NOW, + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, id: LIST_ITEM_ID, listItemIndex: LIST_ITEM_INDEX, meta: META, diff --git a/x-pack/plugins/lists/server/services/items/update_list_item.test.ts b/x-pack/plugins/lists/server/services/items/update_list_item.test.ts index ec44ae1a3b5fd..ae6b6ad3faecf 100644 --- a/x-pack/plugins/lists/server/services/items/update_list_item.test.ts +++ b/x-pack/plugins/lists/server/services/items/update_list_item.test.ts @@ -5,6 +5,9 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { ListItemSchema } from '../../../common/schemas'; import { getListItemResponseMock } from '../../../common/schemas/response/list_item_schema.mock'; @@ -29,7 +32,11 @@ describe('update_list_item', () => { const listItem = getListItemResponseMock(); ((getListItem as unknown) as jest.Mock).mockResolvedValueOnce(listItem); const options = getUpdateListItemOptionsMock(); - const updatedList = await updateListItem(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.update.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _id: 'elastic-id-123' }) + ); + const updatedList = await updateListItem({ ...options, esClient }); const expected: ListItemSchema = { ...getListItemResponseMock(), id: 'elastic-id-123' }; expect(updatedList).toEqual(expected); }); diff --git a/x-pack/plugins/lists/server/services/items/update_list_item.ts b/x-pack/plugins/lists/server/services/items/update_list_item.ts index 7da17ba3c3eb6..645508691acc8 100644 --- a/x-pack/plugins/lists/server/services/items/update_list_item.ts +++ b/x-pack/plugins/lists/server/services/items/update_list_item.ts @@ -6,7 +6,7 @@ */ import { CreateDocumentResponse } from 'elasticsearch'; -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { Id, @@ -25,7 +25,7 @@ export interface UpdateListItemOptions { _version: _VersionOrUndefined; id: Id; value: string | null | undefined; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listItemIndex: string; user: string; meta: MetaOrUndefined; @@ -36,14 +36,14 @@ export const updateListItem = async ({ _version, id, value, - callCluster, + esClient, listItemIndex, user, meta, dateNow, }: UpdateListItemOptions): Promise => { const updatedAt = dateNow ?? new Date().toISOString(); - const listItem = await getListItem({ callCluster, id, listItemIndex }); + const listItem = await getListItem({ esClient, id, listItemIndex }); if (listItem == null) { return null; } else { @@ -62,7 +62,7 @@ export const updateListItem = async ({ ...elasticQuery, }; - const response = await callCluster('update', { + const { body: response } = await esClient.update({ ...decodeVersion(_version), body: { doc, diff --git a/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.mock.ts b/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.mock.ts index c59f95e152ba8..949b7a5c1a691 100644 --- a/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.mock.ts +++ b/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.mock.ts @@ -5,7 +5,9 @@ * 2.0. */ -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { ImportListItemsToStreamOptions, WriteBufferToItemsOptions } from '../items'; import { LIST_ID, @@ -21,9 +23,9 @@ import { getConfigMockDecoded } from '../../config.mock'; import { TestReadable } from './test_readable.mock'; export const getImportListItemsToStreamOptionsMock = (): ImportListItemsToStreamOptions => ({ - callCluster: getCallClusterMock(), config: getConfigMockDecoded(), deserializer: undefined, + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, listId: LIST_ID, listIndex: LIST_INDEX, listItemIndex: LIST_ITEM_INDEX, @@ -37,8 +39,8 @@ export const getImportListItemsToStreamOptionsMock = (): ImportListItemsToStream export const getWriteBufferToItemsOptionsMock = (): WriteBufferToItemsOptions => ({ buffer: [], - callCluster: getCallClusterMock(), deserializer: undefined, + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, meta: META, diff --git a/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.ts b/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.ts index 1dd9aa6d97368..8450890cfa355 100644 --- a/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.ts +++ b/x-pack/plugins/lists/server/services/items/write_lines_to_bulk_list_items.ts @@ -7,7 +7,7 @@ import { Readable } from 'stream'; -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { createListIfItDoesNotExist } from '../lists/create_list_if_it_does_not_exist'; import { @@ -31,7 +31,7 @@ export interface ImportListItemsToStreamOptions { deserializer: DeserializerOrUndefined; serializer: SerializerOrUndefined; stream: Readable; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listItemIndex: string; type: Type; user: string; @@ -45,7 +45,7 @@ export const importListItemsToStream = ({ serializer, listId, stream, - callCluster, + esClient, listItemIndex, listIndex, type, @@ -62,9 +62,9 @@ export const importListItemsToStream = ({ fileName = fileNameEmitted; if (listId == null) { list = await createListIfItDoesNotExist({ - callCluster, description: `File uploaded from file system of ${fileNameEmitted}`, deserializer, + esClient, id: fileNameEmitted, immutable: false, listIndex, @@ -83,8 +83,8 @@ export const importListItemsToStream = ({ if (listId != null) { await writeBufferToItems({ buffer: lines, - callCluster, deserializer, + esClient, listId, listItemIndex, meta, @@ -95,8 +95,8 @@ export const importListItemsToStream = ({ } else if (fileName != null) { await writeBufferToItems({ buffer: lines, - callCluster, deserializer, + esClient, listId: fileName, listItemIndex, meta, @@ -117,7 +117,7 @@ export interface WriteBufferToItemsOptions { listId: string; deserializer: DeserializerOrUndefined; serializer: SerializerOrUndefined; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listItemIndex: string; buffer: string[]; type: Type; @@ -131,7 +131,7 @@ export interface LinesResult { export const writeBufferToItems = async ({ listId, - callCluster, + esClient, deserializer, serializer, listItemIndex, @@ -141,8 +141,8 @@ export const writeBufferToItems = async ({ meta, }: WriteBufferToItemsOptions): Promise => { await createListItemsBulk({ - callCluster, deserializer, + esClient, listId, listItemIndex, meta, diff --git a/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.test.ts b/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.test.ts index 2f161369c84fb..b096adb2d1a13 100644 --- a/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.test.ts +++ b/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.test.ts @@ -5,8 +5,10 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { getSearchListItemMock } from '../../../common/schemas/elastic_response/search_es_list_item_schema.mock'; -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; import { LIST_ID, LIST_ITEM_INDEX } from '../../../common/constants.mock'; import { @@ -38,8 +40,11 @@ describe('write_list_items_to_stream', () => { const options = getExportListItemsToStreamOptionsMock(); const firstResponse = getSearchListItemMock(); firstResponse.hits.hits = []; - options.callCluster = getCallClusterMock(firstResponse); - exportListItemsToStream(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(firstResponse) + ); + exportListItemsToStream({ ...options, esClient }); let chunks: string[] = []; options.stream.on('data', (chunk: Buffer) => { @@ -54,7 +59,12 @@ describe('write_list_items_to_stream', () => { test('It exports single list item to the stream', (done) => { const options = getExportListItemsToStreamOptionsMock(); - exportListItemsToStream(options); + const response = getSearchListItemMock(); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(response) + ); + exportListItemsToStream({ ...options, esClient }); let chunks: string[] = []; options.stream.on('data', (chunk: Buffer) => { @@ -72,8 +82,11 @@ describe('write_list_items_to_stream', () => { const firstResponse = getSearchListItemMock(); const secondResponse = getSearchListItemMock(); firstResponse.hits.hits = [...firstResponse.hits.hits, ...secondResponse.hits.hits]; - options.callCluster = getCallClusterMock(firstResponse); - exportListItemsToStream(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(firstResponse) + ); + exportListItemsToStream({ ...options, esClient }); let chunks: string[] = []; options.stream.on('data', (chunk: Buffer) => { @@ -95,12 +108,14 @@ describe('write_list_items_to_stream', () => { const secondResponse = getSearchListItemMock(); secondResponse.hits.hits[0]._source.ip = '255.255.255.255'; - options.callCluster = jest - .fn() - .mockResolvedValueOnce(firstResponse) - .mockResolvedValueOnce(secondResponse); - - exportListItemsToStream(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise(firstResponse) + ); + esClient.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise(secondResponse) + ); + exportListItemsToStream({ ...options, esClient }); let chunks: string[] = []; options.stream.on('data', (chunk: Buffer) => { @@ -117,7 +132,12 @@ describe('write_list_items_to_stream', () => { describe('writeNextResponse', () => { test('It returns an empty searchAfter response when there is no sort defined', async () => { const options = getWriteNextResponseOptions(); - const searchAfter = await writeNextResponse(options); + const listItem = getSearchListItemMock(); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(listItem) + ); + const searchAfter = await writeNextResponse({ ...options, esClient }); expect(searchAfter).toEqual(undefined); }); @@ -125,8 +145,11 @@ describe('write_list_items_to_stream', () => { const listItem = getSearchListItemMock(); listItem.hits.hits[0].sort = ['sort-value-1']; const options = getWriteNextResponseOptions(); - options.callCluster = getCallClusterMock(listItem); - const searchAfter = await writeNextResponse(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(listItem) + ); + const searchAfter = await writeNextResponse({ ...options, esClient }); expect(searchAfter).toEqual(['sort-value-1']); }); @@ -134,8 +157,11 @@ describe('write_list_items_to_stream', () => { const listItem = getSearchListItemMock(); listItem.hits.hits = []; const options = getWriteNextResponseOptions(); - options.callCluster = getCallClusterMock(listItem); - const searchAfter = await writeNextResponse(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(listItem) + ); + const searchAfter = await writeNextResponse({ ...options, esClient }); expect(searchAfter).toEqual(undefined); }); }); @@ -183,11 +209,11 @@ describe('write_list_items_to_stream', () => { search_after: ['string 1', 'string 2'], sort: [{ tie_breaker_id: 'asc' }], }, - ignoreUnavailable: true, + ignore_unavailable: true, index: LIST_ITEM_INDEX, size: 100, }; - expect(options.callCluster).toBeCalledWith('search', expected); + expect(options.esClient.search).toBeCalledWith(expected); }); test('It returns a simple response with expected values and size changed', async () => { @@ -201,11 +227,11 @@ describe('write_list_items_to_stream', () => { search_after: ['string 1', 'string 2'], sort: [{ tie_breaker_id: 'asc' }], }, - ignoreUnavailable: true, + ignore_unavailable: true, index: LIST_ITEM_INDEX, size: 33, }; - expect(options.callCluster).toBeCalledWith('search', expected); + expect(options.esClient.search).toBeCalledWith(expected); }); }); diff --git a/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.ts b/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.ts index 58b09d9e466d3..9bdcb58835ab0 100644 --- a/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.ts +++ b/x-pack/plugins/lists/server/services/items/write_list_items_to_stream.ts @@ -8,7 +8,7 @@ import { PassThrough } from 'stream'; import { SearchResponse } from 'elasticsearch'; -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { SearchEsListItemSchema } from '../../../common/schemas'; import { ErrorWithStatusCode } from '../../error_with_status_code'; @@ -22,7 +22,7 @@ export const SIZE = 100; export interface ExportListItemsToStreamOptions { listId: string; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listItemIndex: string; stream: PassThrough; stringToAppend: string | null | undefined; @@ -30,7 +30,7 @@ export interface ExportListItemsToStreamOptions { export const exportListItemsToStream = ({ listId, - callCluster, + esClient, stream, listItemIndex, stringToAppend, @@ -39,7 +39,7 @@ export const exportListItemsToStream = ({ // and prevent the async await from bubbling up to the caller setTimeout(async () => { let searchAfter = await writeNextResponse({ - callCluster, + esClient, listId, listItemIndex, searchAfter: undefined, @@ -48,7 +48,7 @@ export const exportListItemsToStream = ({ }); while (searchAfter != null) { searchAfter = await writeNextResponse({ - callCluster, + esClient, listId, listItemIndex, searchAfter, @@ -62,7 +62,7 @@ export const exportListItemsToStream = ({ export interface WriteNextResponseOptions { listId: string; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listItemIndex: string; stream: PassThrough; searchAfter: string[] | undefined; @@ -71,14 +71,14 @@ export interface WriteNextResponseOptions { export const writeNextResponse = async ({ listId, - callCluster, + esClient, stream, listItemIndex, searchAfter, stringToAppend, }: WriteNextResponseOptions): Promise => { const response = await getResponse({ - callCluster, + esClient, listId, listItemIndex, searchAfter, @@ -102,7 +102,7 @@ export const getSearchAfterFromResponse = ({ : undefined; export interface GetResponseOptions { - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listId: string; searchAfter: undefined | string[]; listItemIndex: string; @@ -110,26 +110,28 @@ export interface GetResponseOptions { } export const getResponse = async ({ - callCluster, + esClient, searchAfter, listId, listItemIndex, size = SIZE, }: GetResponseOptions): Promise> => { - return callCluster('search', { - body: { - query: { - term: { - list_id: listId, + return (( + await esClient.search({ + body: { + query: { + term: { + list_id: listId, + }, }, + search_after: searchAfter, + sort: [{ tie_breaker_id: 'asc' }], }, - search_after: searchAfter, - sort: [{ tie_breaker_id: 'asc' }], - }, - ignoreUnavailable: true, - index: listItemIndex, - size, - }); + ignore_unavailable: true, + index: listItemIndex, + size, + }) + ).body as unknown) as SearchResponse; }; export interface WriteResponseHitsToStreamOptions { diff --git a/x-pack/plugins/lists/server/services/items/write_list_items_to_streams.mock.ts b/x-pack/plugins/lists/server/services/items/write_list_items_to_streams.mock.ts index 676613a205042..3de8fdb0c9df6 100644 --- a/x-pack/plugins/lists/server/services/items/write_list_items_to_streams.mock.ts +++ b/x-pack/plugins/lists/server/services/items/write_list_items_to_streams.mock.ts @@ -7,8 +7,10 @@ import { Stream } from 'stream'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { getSearchListItemMock } from '../../../common/schemas/elastic_response/search_es_list_item_schema.mock'; -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; import { ExportListItemsToStreamOptions, GetResponseOptions, @@ -18,7 +20,7 @@ import { import { LIST_ID, LIST_ITEM_INDEX } from '../../../common/constants.mock'; export const getExportListItemsToStreamOptionsMock = (): ExportListItemsToStreamOptions => ({ - callCluster: getCallClusterMock(getSearchListItemMock()), + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, stream: new Stream.PassThrough(), @@ -26,7 +28,7 @@ export const getExportListItemsToStreamOptionsMock = (): ExportListItemsToStream }); export const getWriteNextResponseOptions = (): WriteNextResponseOptions => ({ - callCluster: getCallClusterMock(getSearchListItemMock()), + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, searchAfter: [], @@ -35,7 +37,7 @@ export const getWriteNextResponseOptions = (): WriteNextResponseOptions => ({ }); export const getResponseOptionsMock = (): GetResponseOptions => ({ - callCluster: getCallClusterMock(), + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, listId: LIST_ID, listItemIndex: LIST_ITEM_INDEX, searchAfter: [], diff --git a/x-pack/plugins/lists/server/services/lists/create_list.mock.ts b/x-pack/plugins/lists/server/services/lists/create_list.mock.ts index c3ddb3bfc56ae..5e9c8e38c3f5e 100644 --- a/x-pack/plugins/lists/server/services/lists/create_list.mock.ts +++ b/x-pack/plugins/lists/server/services/lists/create_list.mock.ts @@ -5,7 +5,9 @@ * 2.0. */ -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { CreateListOptions } from '../lists'; import { DATE_NOW, @@ -22,10 +24,10 @@ import { } from '../../../common/constants.mock'; export const getCreateListOptionsMock = (): CreateListOptions => ({ - callCluster: getCallClusterMock(), dateNow: DATE_NOW, description: DESCRIPTION, deserializer: undefined, + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, id: LIST_ID, immutable: IMMUTABLE, listIndex: LIST_INDEX, diff --git a/x-pack/plugins/lists/server/services/lists/create_list.test.ts b/x-pack/plugins/lists/server/services/lists/create_list.test.ts index dbbb7d6e6c5f1..6fc556955fae3 100644 --- a/x-pack/plugins/lists/server/services/lists/create_list.test.ts +++ b/x-pack/plugins/lists/server/services/lists/create_list.test.ts @@ -5,6 +5,9 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { ListSchema } from '../../../common/schemas'; import { getListResponseMock } from '../../../common/schemas/response/list_schema.mock'; import { getIndexESListMock } from '../../../common/schemas/elastic_query/index_es_list_schema.mock'; @@ -24,7 +27,11 @@ describe('crete_list', () => { test('it returns a list as expected with the id changed out for the elastic id', async () => { const options = getCreateListOptionsMock(); - const list = await createList(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.index.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _id: 'elastic-id-123' }) + ); + const list = await createList({ ...options, esClient }); const expected: ListSchema = { ...getListResponseMock(), id: 'elastic-id-123' }; expect(list).toEqual(expected); }); @@ -35,7 +42,11 @@ describe('crete_list', () => { deserializer: '{{value}}', serializer: '(?)', }; - const list = await createList(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.index.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _id: 'elastic-id-123' }) + ); + const list = await createList({ ...options, esClient }); const expected: ListSchema = { ...getListResponseMock(), deserializer: '{{value}}', @@ -45,7 +56,7 @@ describe('crete_list', () => { expect(list).toEqual(expected); }); - test('It calls "callCluster" with body, index, and listIndex', async () => { + test('It calls "esClient" with body, index, and listIndex', async () => { const options = getCreateListOptionsMock(); await createList(options); const body = getIndexESListMock(); @@ -55,13 +66,17 @@ describe('crete_list', () => { index: LIST_INDEX, refresh: 'wait_for', }; - expect(options.callCluster).toBeCalledWith('index', expected); + expect(options.esClient.index).toBeCalledWith(expected); }); test('It returns an auto-generated id if id is sent in undefined', async () => { const options = getCreateListOptionsMock(); options.id = undefined; - const list = await createList(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.index.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _id: 'elastic-id-123' }) + ); + const list = await createList({ ...options, esClient }); const expected: ListSchema = { ...getListResponseMock(), id: 'elastic-id-123' }; expect(list).toEqual(expected); }); diff --git a/x-pack/plugins/lists/server/services/lists/create_list.ts b/x-pack/plugins/lists/server/services/lists/create_list.ts index 999b29bcb08fd..2671a23266ec9 100644 --- a/x-pack/plugins/lists/server/services/lists/create_list.ts +++ b/x-pack/plugins/lists/server/services/lists/create_list.ts @@ -7,7 +7,7 @@ import uuid from 'uuid'; import { CreateDocumentResponse } from 'elasticsearch'; -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { encodeHitVersion } from '../utils/encode_hit_version'; import { @@ -31,7 +31,7 @@ export interface CreateListOptions { type: Type; name: Name; description: Description; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listIndex: string; user: string; meta: MetaOrUndefined; @@ -48,7 +48,7 @@ export const createList = async ({ name, type, description, - callCluster, + esClient, listIndex, user, meta, @@ -73,7 +73,7 @@ export const createList = async ({ updated_by: user, version, }; - const response = await callCluster('index', { + const { body: response } = await esClient.index({ body, id, index: listIndex, diff --git a/x-pack/plugins/lists/server/services/lists/create_list_if_it_does_not_exist.ts b/x-pack/plugins/lists/server/services/lists/create_list_if_it_does_not_exist.ts index 0f1fd196d3dc2..5325d951626c7 100644 --- a/x-pack/plugins/lists/server/services/lists/create_list_if_it_does_not_exist.ts +++ b/x-pack/plugins/lists/server/services/lists/create_list_if_it_does_not_exist.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { Description, @@ -31,7 +31,7 @@ export interface CreateListIfItDoesNotExistOptions { serializer: SerializerOrUndefined; description: Description; immutable: Immutable; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listIndex: string; user: string; meta: MetaOrUndefined; @@ -46,7 +46,7 @@ export const createListIfItDoesNotExist = async ({ type, description, deserializer, - callCluster, + esClient, listIndex, user, meta, @@ -56,13 +56,13 @@ export const createListIfItDoesNotExist = async ({ version, immutable, }: CreateListIfItDoesNotExistOptions): Promise => { - const list = await getList({ callCluster, id, listIndex }); + const list = await getList({ esClient, id, listIndex }); if (list == null) { return createList({ - callCluster, dateNow, description, deserializer, + esClient, id, immutable, listIndex, diff --git a/x-pack/plugins/lists/server/services/lists/delete_list.mock.ts b/x-pack/plugins/lists/server/services/lists/delete_list.mock.ts index f231213753762..569083aad40db 100644 --- a/x-pack/plugins/lists/server/services/lists/delete_list.mock.ts +++ b/x-pack/plugins/lists/server/services/lists/delete_list.mock.ts @@ -5,12 +5,14 @@ * 2.0. */ -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { DeleteListOptions } from '../lists'; import { LIST_ID, LIST_INDEX, LIST_ITEM_INDEX } from '../../../common/constants.mock'; export const getDeleteListOptionsMock = (): DeleteListOptions => ({ - callCluster: getCallClusterMock(), + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, id: LIST_ID, listIndex: LIST_INDEX, listItemIndex: LIST_ITEM_INDEX, diff --git a/x-pack/plugins/lists/server/services/lists/delete_list.test.ts b/x-pack/plugins/lists/server/services/lists/delete_list.test.ts index 8742123238717..9ceecbc299bab 100644 --- a/x-pack/plugins/lists/server/services/lists/delete_list.test.ts +++ b/x-pack/plugins/lists/server/services/lists/delete_list.test.ts @@ -48,9 +48,9 @@ describe('delete_list', () => { const deleteByQuery = { body: { query: { term: { list_id: LIST_ID } } }, index: LIST_ITEM_INDEX, - refresh: 'wait_for', + refresh: false, }; - expect(options.callCluster).toBeCalledWith('deleteByQuery', deleteByQuery); + expect(options.esClient.deleteByQuery).toBeCalledWith(deleteByQuery); }); test('Delete calls "delete" second if a list is returned from getList', async () => { @@ -61,15 +61,15 @@ describe('delete_list', () => { const deleteQuery = { id: LIST_ID, index: LIST_INDEX, - refresh: 'wait_for', + refresh: false, }; - expect(options.callCluster).toHaveBeenNthCalledWith(2, 'delete', deleteQuery); + expect(options.esClient.delete).toHaveBeenNthCalledWith(1, deleteQuery); }); test('Delete does not call data client if the list returns null', async () => { ((getList as unknown) as jest.Mock).mockResolvedValueOnce(null); const options = getDeleteListOptionsMock(); await deleteList(options); - expect(options.callCluster).not.toHaveBeenCalled(); + expect(options.esClient.delete).not.toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/lists/server/services/lists/delete_list.ts b/x-pack/plugins/lists/server/services/lists/delete_list.ts index cac0189d789b6..4fe200bff436f 100644 --- a/x-pack/plugins/lists/server/services/lists/delete_list.ts +++ b/x-pack/plugins/lists/server/services/lists/delete_list.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { Id, ListSchema } from '../../../common/schemas'; @@ -13,22 +13,22 @@ import { getList } from './get_list'; export interface DeleteListOptions { id: Id; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listIndex: string; listItemIndex: string; } export const deleteList = async ({ id, - callCluster, + esClient, listIndex, listItemIndex, }: DeleteListOptions): Promise => { - const list = await getList({ callCluster, id, listIndex }); + const list = await getList({ esClient, id, listIndex }); if (list == null) { return null; } else { - await callCluster('deleteByQuery', { + await esClient.deleteByQuery({ body: { query: { term: { @@ -37,13 +37,13 @@ export const deleteList = async ({ }, }, index: listItemIndex, - refresh: 'wait_for', + refresh: false, }); - await callCluster('delete', { + await esClient.delete({ id, index: listIndex, - refresh: 'wait_for', + refresh: false, }); return list; } diff --git a/x-pack/plugins/lists/server/services/lists/find_list.ts b/x-pack/plugins/lists/server/services/lists/find_list.ts index c6b995c5102c8..c5a398b0a1ad0 100644 --- a/x-pack/plugins/lists/server/services/lists/find_list.ts +++ b/x-pack/plugins/lists/server/services/lists/find_list.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { SearchResponse } from 'elasticsearch'; import { @@ -34,12 +34,12 @@ interface FindListOptions { page: Page; sortField: SortFieldOrUndefined; sortOrder: SortOrderOrUndefined; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listIndex: string; } export const findList = async ({ - callCluster, + esClient, currentIndexPosition, filter, page, @@ -52,8 +52,8 @@ export const findList = async ({ const query = getQueryFilter({ filter }); const scroll = await scrollToStartPage({ - callCluster, currentIndexPosition, + esClient, filter, hopSize: 100, index: listIndex, @@ -64,25 +64,25 @@ export const findList = async ({ sortOrder, }); - const { count } = await callCluster('count', { + const { body: totalCount } = await esClient.count({ body: { query, }, - ignoreUnavailable: true, + ignore_unavailable: true, index: listIndex, }); if (scroll.validSearchAfterFound) { - // Note: This typing of response = await callCluster> + // Note: This typing of response = await esClient> // is because when you pass in seq_no_primary_term: true it does a "fall through" type and you have // to explicitly define the type . - const response = await callCluster>('search', { + const { body: response } = await esClient.search>({ body: { query, search_after: scroll.searchAfter, sort: getSortWithTieBreaker({ sortField, sortOrder }), }, - ignoreUnavailable: true, + ignore_unavailable: true, index: listIndex, seq_no_primary_term: true, size: perPage, @@ -96,7 +96,7 @@ export const findList = async ({ data: transformElasticToList({ response }), page, per_page: perPage, - total: count, + total: totalCount.count, }; } else { return { @@ -104,7 +104,7 @@ export const findList = async ({ data: [], page, per_page: perPage, - total: count, + total: totalCount.count, }; } }; diff --git a/x-pack/plugins/lists/server/services/lists/get_list.test.ts b/x-pack/plugins/lists/server/services/lists/get_list.test.ts index 9d1b8d8d02fe8..930a52266ba41 100644 --- a/x-pack/plugins/lists/server/services/lists/get_list.test.ts +++ b/x-pack/plugins/lists/server/services/lists/get_list.test.ts @@ -5,9 +5,11 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { getSearchListMock } from '../../../common/schemas/elastic_response/search_es_list_schema.mock'; import { getListResponseMock } from '../../../common/schemas/response/list_schema.mock'; -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; import { LIST_ID, LIST_INDEX } from '../../../common/constants.mock'; import { getList } from './get_list'; @@ -23,8 +25,11 @@ describe('get_list', () => { test('it returns a list as expected if the list is found', async () => { const data = getSearchListMock(); - const callCluster = getCallClusterMock(data); - const list = await getList({ callCluster, id: LIST_ID, listIndex: LIST_INDEX }); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(data) + ); + const list = await getList({ esClient, id: LIST_ID, listIndex: LIST_INDEX }); const expected = getListResponseMock(); expect(list).toEqual(expected); }); @@ -32,8 +37,11 @@ describe('get_list', () => { test('it returns null if the search is empty', async () => { const data = getSearchListMock(); data.hits.hits = []; - const callCluster = getCallClusterMock(data); - const list = await getList({ callCluster, id: LIST_ID, listIndex: LIST_INDEX }); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(data) + ); + const list = await getList({ esClient, id: LIST_ID, listIndex: LIST_INDEX }); expect(list).toEqual(null); }); }); diff --git a/x-pack/plugins/lists/server/services/lists/get_list.ts b/x-pack/plugins/lists/server/services/lists/get_list.ts index a4c45ef6ab0d4..50e6d08dd80ff 100644 --- a/x-pack/plugins/lists/server/services/lists/get_list.ts +++ b/x-pack/plugins/lists/server/services/lists/get_list.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { SearchResponse } from 'elasticsearch'; import { Id, ListSchema, SearchEsListSchema } from '../../../common/schemas'; @@ -13,19 +13,19 @@ import { transformElasticToList } from '../utils/transform_elastic_to_list'; interface GetListOptions { id: Id; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listIndex: string; } export const getList = async ({ id, - callCluster, + esClient, listIndex, }: GetListOptions): Promise => { - // Note: This typing of response = await callCluster> + // Note: This typing of response = await esClient> // is because when you pass in seq_no_primary_term: true it does a "fall through" type and you have // to explicitly define the type . - const response = await callCluster>('search', { + const { body: response } = await esClient.search>({ body: { query: { term: { @@ -33,7 +33,7 @@ export const getList = async ({ }, }, }, - ignoreUnavailable: true, + ignore_unavailable: true, index: listIndex, seq_no_primary_term: true, }); diff --git a/x-pack/plugins/lists/server/services/lists/list_client.mock.ts b/x-pack/plugins/lists/server/services/lists/list_client.mock.ts index c49f73cfb0009..08c14534ac345 100644 --- a/x-pack/plugins/lists/server/services/lists/list_client.mock.ts +++ b/x-pack/plugins/lists/server/services/lists/list_client.mock.ts @@ -5,11 +5,13 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { getFoundListItemSchemaMock } from '../../../common/schemas/response/found_list_item_schema.mock'; import { getFoundListSchemaMock } from '../../../common/schemas/response/found_list_schema.mock'; import { getListItemResponseMock } from '../../../common/schemas/response/list_item_schema.mock'; import { getListResponseMock } from '../../../common/schemas/response/list_schema.mock'; -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; import { IMPORT_BUFFER_SIZE, IMPORT_TIMEOUT, @@ -63,7 +65,6 @@ export class ListClientMock extends ListClient { export const getListClientMock = (): ListClient => { const mock = new ListClientMock({ - callCluster: getCallClusterMock(), config: { enabled: true, importBufferSize: IMPORT_BUFFER_SIZE, @@ -72,6 +73,7 @@ export const getListClientMock = (): ListClient => { listItemIndex: LIST_ITEM_INDEX, maxImportPayloadBytes: MAX_IMPORT_PAYLOAD_BYTES, }, + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, spaceId: 'default', user: 'elastic', }); diff --git a/x-pack/plugins/lists/server/services/lists/list_client.ts b/x-pack/plugins/lists/server/services/lists/list_client.ts index 1d10dc8eff926..0b9bfbed28d83 100644 --- a/x-pack/plugins/lists/server/services/lists/list_client.ts +++ b/x-pack/plugins/lists/server/services/lists/list_client.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { FoundListItemSchema, @@ -80,13 +80,13 @@ export class ListClient { private readonly spaceId: string; private readonly user: string; private readonly config: ConfigType; - private readonly callCluster: LegacyAPICaller; + private readonly esClient: ElasticsearchClient; - constructor({ spaceId, user, config, callCluster }: ConstructorOptions) { + constructor({ spaceId, user, config, esClient }: ConstructorOptions) { this.spaceId = spaceId; this.user = user; this.config = config; - this.callCluster = callCluster; + this.esClient = esClient; } public getListIndex = (): string => { @@ -106,9 +106,9 @@ export class ListClient { }; public getList = async ({ id }: GetListOptions): Promise => { - const { callCluster } = this; + const { esClient } = this; const listIndex = this.getListIndex(); - return getList({ callCluster, id, listIndex }); + return getList({ esClient, id, listIndex }); }; public createList = async ({ @@ -122,12 +122,12 @@ export class ListClient { meta, version, }: CreateListOptions): Promise => { - const { callCluster, user } = this; + const { esClient, user } = this; const listIndex = this.getListIndex(); return createList({ - callCluster, description, deserializer, + esClient, id, immutable, listIndex, @@ -151,12 +151,12 @@ export class ListClient { meta, version, }: CreateListIfItDoesNotExistOptions): Promise => { - const { callCluster, user } = this; + const { esClient, user } = this; const listIndex = this.getListIndex(); return createListIfItDoesNotExist({ - callCluster, description, deserializer, + esClient, id, immutable, listIndex, @@ -170,51 +170,51 @@ export class ListClient { }; public getListIndexExists = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listIndex = this.getListIndex(); - return getIndexExists(callCluster, listIndex); + return getIndexExists(esClient, listIndex); }; public getListItemIndexExists = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listItemIndex = this.getListItemIndex(); - return getIndexExists(callCluster, listItemIndex); + return getIndexExists(esClient, listItemIndex); }; public createListBootStrapIndex = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listIndex = this.getListIndex(); - return createBootstrapIndex(callCluster, listIndex); + return createBootstrapIndex(esClient, listIndex); }; public createListItemBootStrapIndex = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listItemIndex = this.getListItemIndex(); - return createBootstrapIndex(callCluster, listItemIndex); + return createBootstrapIndex(esClient, listItemIndex); }; public getListPolicyExists = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listIndex = this.getListIndex(); - return getPolicyExists(callCluster, listIndex); + return getPolicyExists(esClient, listIndex); }; public getListItemPolicyExists = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listsItemIndex = this.getListItemIndex(); - return getPolicyExists(callCluster, listsItemIndex); + return getPolicyExists(esClient, listsItemIndex); }; public getListTemplateExists = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listIndex = this.getListIndex(); - return getTemplateExists(callCluster, listIndex); + return getTemplateExists(esClient, listIndex); }; public getListItemTemplateExists = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listItemIndex = this.getListItemIndex(); - return getTemplateExists(callCluster, listItemIndex); + return getTemplateExists(esClient, listItemIndex); }; public getListTemplate = (): Record => { @@ -228,71 +228,71 @@ export class ListClient { }; public setListTemplate = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const template = this.getListTemplate(); const listIndex = this.getListIndex(); - return setTemplate(callCluster, listIndex, template); + return setTemplate(esClient, listIndex, template); }; public setListItemTemplate = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const template = this.getListItemTemplate(); const listItemIndex = this.getListItemIndex(); - return setTemplate(callCluster, listItemIndex, template); + return setTemplate(esClient, listItemIndex, template); }; public setListPolicy = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listIndex = this.getListIndex(); - return setPolicy(callCluster, listIndex, listPolicy); + return setPolicy(esClient, listIndex, listPolicy); }; public setListItemPolicy = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listItemIndex = this.getListItemIndex(); - return setPolicy(callCluster, listItemIndex, listsItemsPolicy); + return setPolicy(esClient, listItemIndex, listsItemsPolicy); }; public deleteListIndex = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listIndex = this.getListIndex(); - return deleteAllIndex(callCluster, `${listIndex}-*`); + return deleteAllIndex(esClient, `${listIndex}-*`); }; public deleteListItemIndex = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listItemIndex = this.getListItemIndex(); - return deleteAllIndex(callCluster, `${listItemIndex}-*`); + return deleteAllIndex(esClient, `${listItemIndex}-*`); }; public deleteListPolicy = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listIndex = this.getListIndex(); - return deletePolicy(callCluster, listIndex); + return deletePolicy(esClient, listIndex); }; public deleteListItemPolicy = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listItemIndex = this.getListItemIndex(); - return deletePolicy(callCluster, listItemIndex); + return deletePolicy(esClient, listItemIndex); }; public deleteListTemplate = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listIndex = this.getListIndex(); - return deleteTemplate(callCluster, listIndex); + return deleteTemplate(esClient, listIndex); }; public deleteListItemTemplate = async (): Promise => { - const { callCluster } = this; + const { esClient } = this; const listItemIndex = this.getListItemIndex(); - return deleteTemplate(callCluster, listItemIndex); + return deleteTemplate(esClient, listItemIndex); }; public deleteListItem = async ({ id }: DeleteListItemOptions): Promise => { - const { callCluster } = this; + const { esClient } = this; const listItemIndex = this.getListItemIndex(); - return deleteListItem({ callCluster, id, listItemIndex }); + return deleteListItem({ esClient, id, listItemIndex }); }; public deleteListItemByValue = async ({ @@ -300,10 +300,10 @@ export class ListClient { value, type, }: DeleteListItemByValueOptions): Promise => { - const { callCluster } = this; + const { esClient } = this; const listItemIndex = this.getListItemIndex(); return deleteListItemByValue({ - callCluster, + esClient, listId, listItemIndex, type, @@ -312,11 +312,11 @@ export class ListClient { }; public deleteList = async ({ id }: DeleteListOptions): Promise => { - const { callCluster } = this; + const { esClient } = this; const listIndex = this.getListIndex(); const listItemIndex = this.getListItemIndex(); return deleteList({ - callCluster, + esClient, id, listIndex, listItemIndex, @@ -328,10 +328,10 @@ export class ListClient { listId, stream, }: ExportListItemsToStreamOptions): void => { - const { callCluster } = this; + const { esClient } = this; const listItemIndex = this.getListItemIndex(); exportListItemsToStream({ - callCluster, + esClient, listId, listItemIndex, stream, @@ -348,13 +348,13 @@ export class ListClient { meta, version, }: ImportListItemsToStreamOptions): Promise => { - const { callCluster, user, config } = this; + const { esClient, user, config } = this; const listItemIndex = this.getListItemIndex(); const listIndex = this.getListIndex(); return importListItemsToStream({ - callCluster, config, deserializer, + esClient, listId, listIndex, listItemIndex, @@ -372,10 +372,10 @@ export class ListClient { value, type, }: GetListItemByValueOptions): Promise => { - const { callCluster } = this; + const { esClient } = this; const listItemIndex = this.getListItemIndex(); return getListItemByValue({ - callCluster, + esClient, listId, listItemIndex, type, @@ -392,11 +392,11 @@ export class ListClient { type, meta, }: CreateListItemOptions): Promise => { - const { callCluster, user } = this; + const { esClient, user } = this; const listItemIndex = this.getListItemIndex(); return createListItem({ - callCluster, deserializer, + esClient, id, listId, listItemIndex, @@ -414,11 +414,11 @@ export class ListClient { value, meta, }: UpdateListItemOptions): Promise => { - const { callCluster, user } = this; + const { esClient, user } = this; const listItemIndex = this.getListItemIndex(); return updateListItem({ _version, - callCluster, + esClient, id, listItemIndex, meta, @@ -435,12 +435,12 @@ export class ListClient { meta, version, }: UpdateListOptions): Promise => { - const { callCluster, user } = this; + const { esClient, user } = this; const listIndex = this.getListIndex(); return updateList({ _version, - callCluster, description, + esClient, id, listIndex, meta, @@ -451,10 +451,10 @@ export class ListClient { }; public getListItem = async ({ id }: GetListItemOptions): Promise => { - const { callCluster } = this; + const { esClient } = this; const listItemIndex = this.getListItemIndex(); return getListItem({ - callCluster, + esClient, id, listItemIndex, }); @@ -465,10 +465,10 @@ export class ListClient { listId, value, }: GetListItemsByValueOptions): Promise => { - const { callCluster } = this; + const { esClient } = this; const listItemIndex = this.getListItemIndex(); return getListItemByValues({ - callCluster, + esClient, listId, listItemIndex, type, @@ -481,10 +481,10 @@ export class ListClient { listId, value, }: SearchListItemByValuesOptions): Promise => { - const { callCluster } = this; + const { esClient } = this; const listItemIndex = this.getListItemIndex(); return searchListItemByValues({ - callCluster, + esClient, listId, listItemIndex, type, @@ -501,11 +501,11 @@ export class ListClient { sortOrder, searchAfter, }: FindListOptions): Promise => { - const { callCluster } = this; + const { esClient } = this; const listIndex = this.getListIndex(); return findList({ - callCluster, currentIndexPosition, + esClient, filter, listIndex, page, @@ -526,12 +526,12 @@ export class ListClient { sortOrder, searchAfter, }: FindListItemOptions): Promise => { - const { callCluster } = this; + const { esClient } = this; const listIndex = this.getListIndex(); const listItemIndex = this.getListItemIndex(); return findListItem({ - callCluster, currentIndexPosition, + esClient, filter, listId, listIndex, diff --git a/x-pack/plugins/lists/server/services/lists/list_client_types.ts b/x-pack/plugins/lists/server/services/lists/list_client_types.ts index 54fd4f83e2d83..1efcd2af5420e 100644 --- a/x-pack/plugins/lists/server/services/lists/list_client_types.ts +++ b/x-pack/plugins/lists/server/services/lists/list_client_types.ts @@ -7,7 +7,7 @@ import { PassThrough, Readable } from 'stream'; -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { Description, @@ -35,7 +35,7 @@ import { import { ConfigType } from '../../config'; export interface ConstructorOptions { - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; config: ConfigType; spaceId: string; user: string; diff --git a/x-pack/plugins/lists/server/services/lists/update_list.mock.ts b/x-pack/plugins/lists/server/services/lists/update_list.mock.ts index 313ab5bb45e2f..5648a8df7dde8 100644 --- a/x-pack/plugins/lists/server/services/lists/update_list.mock.ts +++ b/x-pack/plugins/lists/server/services/lists/update_list.mock.ts @@ -5,7 +5,9 @@ * 2.0. */ -import { getCallClusterMock } from '../../../common/get_call_cluster.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { UpdateListOptions } from '../lists'; import { DATE_NOW, @@ -20,9 +22,9 @@ import { export const getUpdateListOptionsMock = (): UpdateListOptions => ({ _version: undefined, - callCluster: getCallClusterMock(), dateNow: DATE_NOW, description: DESCRIPTION, + esClient: elasticsearchClientMock.createScopedClusterClient().asCurrentUser, id: LIST_ID, listIndex: LIST_INDEX, meta: META, diff --git a/x-pack/plugins/lists/server/services/lists/update_list.test.ts b/x-pack/plugins/lists/server/services/lists/update_list.test.ts index ff9a6f598db23..e2d3b09fe518a 100644 --- a/x-pack/plugins/lists/server/services/lists/update_list.test.ts +++ b/x-pack/plugins/lists/server/services/lists/update_list.test.ts @@ -5,6 +5,9 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; + import { ListSchema } from '../../../common/schemas'; import { getListResponseMock } from '../../../common/schemas/response/list_schema.mock'; @@ -29,7 +32,11 @@ describe('update_list', () => { const list = getListResponseMock(); ((getList as unknown) as jest.Mock).mockResolvedValueOnce(list); const options = getUpdateListOptionsMock(); - const updatedList = await updateList(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.update.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _id: 'elastic-id-123' }) + ); + const updatedList = await updateList({ ...options, esClient }); const expected: ListSchema = { ...getListResponseMock(), id: 'elastic-id-123' }; expect(updatedList).toEqual(expected); }); @@ -42,7 +49,11 @@ describe('update_list', () => { }; ((getList as unknown) as jest.Mock).mockResolvedValueOnce(list); const options = getUpdateListOptionsMock(); - const updatedList = await updateList(options); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.update.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _id: 'elastic-id-123' }) + ); + const updatedList = await updateList({ ...options, esClient }); const expected: ListSchema = { ...getListResponseMock(), deserializer: '{{value}}', diff --git a/x-pack/plugins/lists/server/services/lists/update_list.ts b/x-pack/plugins/lists/server/services/lists/update_list.ts index 05939d86189c5..aa4eb9a8d834f 100644 --- a/x-pack/plugins/lists/server/services/lists/update_list.ts +++ b/x-pack/plugins/lists/server/services/lists/update_list.ts @@ -6,7 +6,7 @@ */ import { CreateDocumentResponse } from 'elasticsearch'; -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { decodeVersion } from '../utils/decode_version'; import { encodeHitVersion } from '../utils/encode_hit_version'; @@ -26,7 +26,7 @@ import { getList } from '.'; export interface UpdateListOptions { _version: _VersionOrUndefined; id: Id; - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; listIndex: string; user: string; name: NameOrUndefined; @@ -41,7 +41,7 @@ export const updateList = async ({ id, name, description, - callCluster, + esClient, listIndex, user, meta, @@ -49,7 +49,7 @@ export const updateList = async ({ version, }: UpdateListOptions): Promise => { const updatedAt = dateNow ?? new Date().toISOString(); - const list = await getList({ callCluster, id, listIndex }); + const list = await getList({ esClient, id, listIndex }); if (list == null) { return null; } else { @@ -61,7 +61,7 @@ export const updateList = async ({ updated_at: updatedAt, updated_by: user, }; - const response = await callCluster('update', { + const { body: response } = await esClient.update({ ...decodeVersion(_version), body: { doc }, id, diff --git a/x-pack/plugins/lists/server/services/utils/get_search_after_scroll.ts b/x-pack/plugins/lists/server/services/utils/get_search_after_scroll.ts index ef9b2b4d93e5f..34359a7a9c697 100644 --- a/x-pack/plugins/lists/server/services/utils/get_search_after_scroll.ts +++ b/x-pack/plugins/lists/server/services/utils/get_search_after_scroll.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; +import { SearchResponse } from 'elasticsearch'; import { Filter, SortFieldOrUndefined, SortOrderOrUndefined } from '../../../common/schemas'; import { Scroll } from '../lists/types'; @@ -16,7 +17,7 @@ import { getSourceWithTieBreaker } from './get_source_with_tie_breaker'; import { TieBreaker, getSearchAfterWithTieBreaker } from './get_search_after_with_tie_breaker'; interface GetSearchAfterOptions { - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; filter: Filter; hops: number; hopSize: number; @@ -27,7 +28,7 @@ interface GetSearchAfterOptions { } export const getSearchAfterScroll = async ({ - callCluster, + esClient, filter, hopSize, hops, @@ -39,14 +40,14 @@ export const getSearchAfterScroll = async ({ const query = getQueryFilter({ filter }); let newSearchAfter = searchAfter; for (let i = 0; i < hops; ++i) { - const response = await callCluster>('search', { + const { body: response } = await esClient.search>>({ body: { _source: getSourceWithTieBreaker({ sortField }), query, search_after: newSearchAfter, sort: getSortWithTieBreaker({ sortField, sortOrder }), }, - ignoreUnavailable: true, + ignore_unavailable: true, index, size: hopSize, }); diff --git a/x-pack/plugins/lists/server/services/utils/scroll_to_start_page.ts b/x-pack/plugins/lists/server/services/utils/scroll_to_start_page.ts index 502c754615416..2b65c0df54a83 100644 --- a/x-pack/plugins/lists/server/services/utils/scroll_to_start_page.ts +++ b/x-pack/plugins/lists/server/services/utils/scroll_to_start_page.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { LegacyAPICaller } from 'kibana/server'; +import { ElasticsearchClient } from 'kibana/server'; import { Filter, SortFieldOrUndefined, SortOrderOrUndefined } from '../../../common/schemas'; import { Scroll } from '../lists/types'; @@ -14,7 +14,7 @@ import { calculateScrollMath } from './calculate_scroll_math'; import { getSearchAfterScroll } from './get_search_after_scroll'; interface ScrollToStartPageOptions { - callCluster: LegacyAPICaller; + esClient: ElasticsearchClient; filter: Filter; sortField: SortFieldOrUndefined; sortOrder: SortOrderOrUndefined; @@ -27,7 +27,7 @@ interface ScrollToStartPageOptions { } export const scrollToStartPage = async ({ - callCluster, + esClient, filter, hopSize, currentIndexPosition, @@ -58,7 +58,7 @@ export const scrollToStartPage = async ({ }; } else if (hops > 0) { const scroll = await getSearchAfterScroll({ - callCluster, + esClient, filter, hopSize, hops, @@ -69,7 +69,7 @@ export const scrollToStartPage = async ({ }); if (scroll.validSearchAfterFound && leftOverAfterHops > 0) { return getSearchAfterScroll({ - callCluster, + esClient, filter, hopSize: leftOverAfterHops, hops: 1, @@ -83,7 +83,7 @@ export const scrollToStartPage = async ({ } } else { return getSearchAfterScroll({ - callCluster, + esClient, filter, hopSize: leftOverAfterHops, hops: 1, diff --git a/x-pack/plugins/lists/server/types.ts b/x-pack/plugins/lists/server/types.ts index c41bfcc0014c8..50d8d4d652a82 100644 --- a/x-pack/plugins/lists/server/types.ts +++ b/x-pack/plugins/lists/server/types.ts @@ -6,9 +6,9 @@ */ import { + ElasticsearchClient, IContextProvider, IRouter, - LegacyAPICaller, RequestHandlerContext, SavedObjectsClientContract, } from 'kibana/server'; @@ -27,7 +27,7 @@ export interface PluginsStart { } export type GetListClientType = ( - dataClient: LegacyAPICaller, + esClient: ElasticsearchClient, spaceId: string, user: string ) => ListClient; diff --git a/x-pack/plugins/monitoring/server/alerts/base_alert.ts b/x-pack/plugins/monitoring/server/alerts/base_alert.ts index 9a2efade7b44f..fbe487f240699 100644 --- a/x-pack/plugins/monitoring/server/alerts/base_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/base_alert.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Logger, LegacyCallAPIOptions } from 'kibana/server'; +import { Logger, ElasticsearchClient } from 'kibana/server'; import { i18n } from '@kbn/i18n'; import { AlertType, @@ -32,7 +32,6 @@ import { fetchClusters } from '../lib/alerts/fetch_clusters'; import { getCcsIndexPattern } from '../lib/alerts/get_ccs_index_pattern'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../common/constants'; import { AlertSeverity } from '../../common/enums'; -import { mbSafeQuery } from '../lib/mb_safe_query'; import { appendMetricbeatIndex } from '../lib/alerts/append_mb_index'; import { parseDuration } from '../../../alerting/common/parse_duration'; import { Globals } from '../static_globals'; @@ -56,12 +55,6 @@ interface AlertOptions { accessorKey?: string; } -type CallCluster = ( - endpoint: string, - clientParams?: Record | undefined, - options?: LegacyCallAPIOptions | undefined -) => Promise; - const defaultAlertOptions = (): AlertOptions => { return { id: '', @@ -233,29 +226,15 @@ export class BaseAlert { `Executing alert with params: ${JSON.stringify(params)} and state: ${JSON.stringify(state)}` ); - const useCallCluster = - Globals.app.monitoringCluster?.callAsInternalUser || services.callCluster; - const callCluster = async ( - endpoint: string, - clientParams?: Record, - options?: LegacyCallAPIOptions - ) => { - return await mbSafeQuery(async () => useCallCluster(endpoint, clientParams, options)); - }; - const availableCcs = Globals.app.config.ui.ccs.enabled - ? await fetchAvailableCcs(callCluster) - : []; - const clusters = await this.fetchClusters( - callCluster, - params as CommonAlertParams, - availableCcs - ); - const data = await this.fetchData(params, callCluster, clusters, availableCcs); + const esClient = services.scopedClusterClient.asCurrentUser; + const availableCcs = Globals.app.config.ui.ccs.enabled ? await fetchAvailableCcs(esClient) : []; + const clusters = await this.fetchClusters(esClient, params as CommonAlertParams, availableCcs); + const data = await this.fetchData(params, esClient, clusters, availableCcs); return await this.processData(data, clusters, services, state); } protected async fetchClusters( - callCluster: CallCluster, + esClient: ElasticsearchClient, params: CommonAlertParams, ccs?: string[] ) { @@ -264,7 +243,7 @@ export class BaseAlert { esIndexPattern = getCcsIndexPattern(esIndexPattern, ccs); } if (!params.limit) { - return await fetchClusters(callCluster, esIndexPattern); + return await fetchClusters(esClient, esIndexPattern); } const limit = parseDuration(params.limit); const rangeFilter = this.alertOptions.fetchClustersRange @@ -275,12 +254,12 @@ export class BaseAlert { }, } : undefined; - return await fetchClusters(callCluster, esIndexPattern, rangeFilter); + return await fetchClusters(esClient, esIndexPattern, rangeFilter); } protected async fetchData( params: CommonAlertParams | unknown, - callCluster: CallCluster, + esClient: ElasticsearchClient, clusters: AlertCluster[], availableCcs: string[] ): Promise> { diff --git a/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_alert.ts b/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_alert.ts index b089b466564e4..6401c5213ee7d 100644 --- a/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/ccr_read_exceptions_alert.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { ElasticsearchClient } from 'kibana/server'; import { BaseAlert } from './base_alert'; import { AlertData, @@ -70,7 +71,7 @@ export class CCRReadExceptionsAlert extends BaseAlert { protected async fetchData( params: CommonAlertParams, - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], availableCcs: string[] ): Promise { @@ -83,7 +84,7 @@ export class CCRReadExceptionsAlert extends BaseAlert { const endMs = +new Date(); const startMs = endMs - duration; const stats = await fetchCCRReadExceptions( - callCluster, + esClient, esIndexPattern, startMs, endMs, diff --git a/x-pack/plugins/monitoring/server/alerts/cluster_health_alert.test.ts b/x-pack/plugins/monitoring/server/alerts/cluster_health_alert.test.ts index 1490a6ce58e04..1c39d6d6b9629 100644 --- a/x-pack/plugins/monitoring/server/alerts/cluster_health_alert.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/cluster_health_alert.test.ts @@ -10,6 +10,7 @@ import { ALERT_CLUSTER_HEALTH } from '../../common/constants'; import { AlertClusterHealthType, AlertSeverity } from '../../common/enums'; import { fetchClusterHealth } from '../lib/alerts/fetch_cluster_health'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; const RealDate = Date; @@ -80,7 +81,7 @@ describe('ClusterHealthAlert', () => { const getState = jest.fn(); const executorOptions = { services: { - callCluster: jest.fn(), + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), alertInstanceFactory: jest.fn().mockImplementation(() => { return { replaceState, diff --git a/x-pack/plugins/monitoring/server/alerts/cluster_health_alert.ts b/x-pack/plugins/monitoring/server/alerts/cluster_health_alert.ts index 15b3a7b486fa2..c5983ae9897fe 100644 --- a/x-pack/plugins/monitoring/server/alerts/cluster_health_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/cluster_health_alert.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { ElasticsearchClient } from 'kibana/server'; import { BaseAlert } from './base_alert'; import { AlertData, @@ -64,7 +65,7 @@ export class ClusterHealthAlert extends BaseAlert { protected async fetchData( params: CommonAlertParams, - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], availableCcs: string[] ): Promise { @@ -72,7 +73,7 @@ export class ClusterHealthAlert extends BaseAlert { if (availableCcs) { esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); } - const healths = await fetchClusterHealth(callCluster, clusters, esIndexPattern); + const healths = await fetchClusterHealth(esClient, clusters, esIndexPattern); return healths.map((clusterHealth) => { const shouldFire = clusterHealth.health !== AlertClusterHealthType.Green; const severity = diff --git a/x-pack/plugins/monitoring/server/alerts/cpu_usage_alert.test.ts b/x-pack/plugins/monitoring/server/alerts/cpu_usage_alert.test.ts index 03342099773ca..be10ba15d2674 100644 --- a/x-pack/plugins/monitoring/server/alerts/cpu_usage_alert.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/cpu_usage_alert.test.ts @@ -9,6 +9,7 @@ import { CpuUsageAlert } from './cpu_usage_alert'; import { ALERT_CPU_USAGE } from '../../common/constants'; import { fetchCpuUsageNodeStats } from '../lib/alerts/fetch_cpu_usage_node_stats'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; const RealDate = Date; @@ -83,7 +84,7 @@ describe('CpuUsageAlert', () => { const getState = jest.fn(); const executorOptions = { services: { - callCluster: jest.fn(), + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), alertInstanceFactory: jest.fn().mockImplementation(() => { return { replaceState, diff --git a/x-pack/plugins/monitoring/server/alerts/cpu_usage_alert.ts b/x-pack/plugins/monitoring/server/alerts/cpu_usage_alert.ts index e95c4402c0f90..438d350d366f8 100644 --- a/x-pack/plugins/monitoring/server/alerts/cpu_usage_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/cpu_usage_alert.ts @@ -7,6 +7,7 @@ import { i18n } from '@kbn/i18n'; import numeral from '@elastic/numeral'; +import { ElasticsearchClient } from 'kibana/server'; import { BaseAlert } from './base_alert'; import { AlertData, @@ -68,7 +69,7 @@ export class CpuUsageAlert extends BaseAlert { protected async fetchData( params: CommonAlertParams, - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], availableCcs: string[] ): Promise { @@ -80,7 +81,7 @@ export class CpuUsageAlert extends BaseAlert { const endMs = +new Date(); const startMs = endMs - duration; const stats = await fetchCpuUsageNodeStats( - callCluster, + esClient, clusters, esIndexPattern, startMs, diff --git a/x-pack/plugins/monitoring/server/alerts/disk_usage_alert.test.ts b/x-pack/plugins/monitoring/server/alerts/disk_usage_alert.test.ts index cdc60faedf0d2..4c40a170e40b4 100644 --- a/x-pack/plugins/monitoring/server/alerts/disk_usage_alert.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/disk_usage_alert.test.ts @@ -9,6 +9,7 @@ import { DiskUsageAlert } from './disk_usage_alert'; import { ALERT_DISK_USAGE } from '../../common/constants'; import { fetchDiskUsageNodeStats } from '../lib/alerts/fetch_disk_usage_node_stats'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; type IDiskUsageAlertMock = DiskUsageAlert & { defaultParams: { @@ -95,7 +96,7 @@ describe('DiskUsageAlert', () => { const getState = jest.fn(); const executorOptions = { services: { - callCluster: jest.fn(), + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), alertInstanceFactory: jest.fn().mockImplementation(() => { return { replaceState, diff --git a/x-pack/plugins/monitoring/server/alerts/disk_usage_alert.ts b/x-pack/plugins/monitoring/server/alerts/disk_usage_alert.ts index 3503195e51b82..8eb36f322168c 100644 --- a/x-pack/plugins/monitoring/server/alerts/disk_usage_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/disk_usage_alert.ts @@ -7,6 +7,7 @@ import { i18n } from '@kbn/i18n'; import numeral from '@elastic/numeral'; +import { ElasticsearchClient } from 'kibana/server'; import { BaseAlert } from './base_alert'; import { AlertData, @@ -67,7 +68,7 @@ export class DiskUsageAlert extends BaseAlert { protected async fetchData( params: CommonAlertParams, - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], availableCcs: string[] ): Promise { @@ -77,7 +78,7 @@ export class DiskUsageAlert extends BaseAlert { } const { duration, threshold } = params; const stats = await fetchDiskUsageNodeStats( - callCluster, + esClient, clusters, esIndexPattern, duration as string, diff --git a/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_alert.test.ts b/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_alert.test.ts index a231cec762191..2bd67298e7b5a 100644 --- a/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_alert.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_alert.test.ts @@ -9,6 +9,7 @@ import { ElasticsearchVersionMismatchAlert } from './elasticsearch_version_misma import { ALERT_ELASTICSEARCH_VERSION_MISMATCH } from '../../common/constants'; import { fetchElasticsearchVersions } from '../lib/alerts/fetch_elasticsearch_versions'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; const RealDate = Date; @@ -84,7 +85,7 @@ describe('ElasticsearchVersionMismatchAlert', () => { const getState = jest.fn(); const executorOptions = { services: { - callCluster: jest.fn(), + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), alertInstanceFactory: jest.fn().mockImplementation(() => { return { replaceState, diff --git a/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_alert.ts b/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_alert.ts index 735e1c43f569a..d51eb99e3a47d 100644 --- a/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/elasticsearch_version_mismatch_alert.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { ElasticsearchClient } from 'kibana/server'; import { BaseAlert } from './base_alert'; import { AlertData, @@ -53,7 +54,7 @@ export class ElasticsearchVersionMismatchAlert extends BaseAlert { protected async fetchData( params: CommonAlertParams, - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], availableCcs: string[] ): Promise { @@ -62,7 +63,7 @@ export class ElasticsearchVersionMismatchAlert extends BaseAlert { esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); } const elasticsearchVersions = await fetchElasticsearchVersions( - callCluster, + esClient, clusters, esIndexPattern, Globals.app.config.ui.max_bucket_size diff --git a/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_alert.test.ts b/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_alert.test.ts index 6252fc59ba246..02a8f59aecfbd 100644 --- a/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_alert.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_alert.test.ts @@ -9,6 +9,7 @@ import { KibanaVersionMismatchAlert } from './kibana_version_mismatch_alert'; import { ALERT_KIBANA_VERSION_MISMATCH } from '../../common/constants'; import { fetchKibanaVersions } from '../lib/alerts/fetch_kibana_versions'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; const RealDate = Date; @@ -87,7 +88,7 @@ describe('KibanaVersionMismatchAlert', () => { const getState = jest.fn(); const executorOptions = { services: { - callCluster: jest.fn(), + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), alertInstanceFactory: jest.fn().mockImplementation(() => { return { replaceState, diff --git a/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_alert.ts b/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_alert.ts index 04ee29f5e47fc..3d6417e8fd64c 100644 --- a/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/kibana_version_mismatch_alert.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { ElasticsearchClient } from 'kibana/server'; import { BaseAlert } from './base_alert'; import { AlertData, @@ -66,7 +67,7 @@ export class KibanaVersionMismatchAlert extends BaseAlert { protected async fetchData( params: CommonAlertParams, - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], availableCcs: string[] ): Promise { @@ -75,7 +76,7 @@ export class KibanaVersionMismatchAlert extends BaseAlert { kibanaIndexPattern = getCcsIndexPattern(kibanaIndexPattern, availableCcs); } const kibanaVersions = await fetchKibanaVersions( - callCluster, + esClient, clusters, kibanaIndexPattern, Globals.app.config.ui.max_bucket_size diff --git a/x-pack/plugins/monitoring/server/alerts/large_shard_size_alert.ts b/x-pack/plugins/monitoring/server/alerts/large_shard_size_alert.ts index b0cbd0edb64f7..2c9e5a04e37e4 100644 --- a/x-pack/plugins/monitoring/server/alerts/large_shard_size_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/large_shard_size_alert.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { ElasticsearchClient } from 'kibana/server'; import { BaseAlert } from './base_alert'; import { AlertData, @@ -59,7 +60,7 @@ export class LargeShardSizeAlert extends BaseAlert { protected async fetchData( params: CommonAlertParams & { indexPattern: string }, - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], availableCcs: string[] ): Promise { @@ -70,7 +71,7 @@ export class LargeShardSizeAlert extends BaseAlert { const { threshold, indexPattern: shardIndexPatterns } = params; const stats = await fetchIndexShardSize( - callCluster, + esClient, clusters, esIndexPattern, threshold!, diff --git a/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.test.ts b/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.test.ts index 0d1c1d20097e5..0bb8ba23cd490 100644 --- a/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.test.ts @@ -10,6 +10,7 @@ import { ALERT_LICENSE_EXPIRATION } from '../../common/constants'; import { AlertSeverity } from '../../common/enums'; import { fetchLicenses } from '../lib/alerts/fetch_licenses'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; const RealDate = Date; @@ -85,7 +86,7 @@ describe('LicenseExpirationAlert', () => { const getState = jest.fn(); const executorOptions = { services: { - callCluster: jest.fn(), + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), alertInstanceFactory: jest.fn().mockImplementation(() => { return { replaceState, diff --git a/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.ts b/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.ts index 9cf50f372ce4f..f5a6f2f7c7e1d 100644 --- a/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/license_expiration_alert.ts @@ -6,6 +6,7 @@ */ import moment from 'moment'; import { i18n } from '@kbn/i18n'; +import { ElasticsearchClient } from 'kibana/server'; import { BaseAlert } from './base_alert'; import { AlertData, @@ -78,7 +79,7 @@ export class LicenseExpirationAlert extends BaseAlert { protected async fetchData( params: CommonAlertParams, - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], availableCcs: string[] ): Promise { @@ -86,7 +87,7 @@ export class LicenseExpirationAlert extends BaseAlert { if (availableCcs) { esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); } - const licenses = await fetchLicenses(callCluster, clusters, esIndexPattern); + const licenses = await fetchLicenses(esClient, clusters, esIndexPattern); return licenses.map((license) => { const { clusterUuid, type, expiryDateMS, status, ccs } = license; diff --git a/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_alert.test.ts b/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_alert.test.ts index 50a826b36d58f..7c73c63f293f3 100644 --- a/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_alert.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_alert.test.ts @@ -9,6 +9,7 @@ import { LogstashVersionMismatchAlert } from './logstash_version_mismatch_alert' import { ALERT_LOGSTASH_VERSION_MISMATCH } from '../../common/constants'; import { fetchLogstashVersions } from '../lib/alerts/fetch_logstash_versions'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; const RealDate = Date; @@ -85,7 +86,7 @@ describe('LogstashVersionMismatchAlert', () => { const getState = jest.fn(); const executorOptions = { services: { - callCluster: jest.fn(), + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), alertInstanceFactory: jest.fn().mockImplementation(() => { return { replaceState, diff --git a/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_alert.ts b/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_alert.ts index 99080b8230ff3..7ee478b17fff8 100644 --- a/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/logstash_version_mismatch_alert.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { ElasticsearchClient } from 'kibana/server'; import { BaseAlert } from './base_alert'; import { AlertData, @@ -53,7 +54,7 @@ export class LogstashVersionMismatchAlert extends BaseAlert { protected async fetchData( params: CommonAlertParams, - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], availableCcs: string[] ): Promise { @@ -62,7 +63,7 @@ export class LogstashVersionMismatchAlert extends BaseAlert { logstashIndexPattern = getCcsIndexPattern(logstashIndexPattern, availableCcs); } const logstashVersions = await fetchLogstashVersions( - callCluster, + esClient, clusters, logstashIndexPattern, Globals.app.config.ui.max_bucket_size diff --git a/x-pack/plugins/monitoring/server/alerts/memory_usage_alert.ts b/x-pack/plugins/monitoring/server/alerts/memory_usage_alert.ts index 05dc0271cf3f7..06cd90ca80729 100644 --- a/x-pack/plugins/monitoring/server/alerts/memory_usage_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/memory_usage_alert.ts @@ -7,6 +7,7 @@ import { i18n } from '@kbn/i18n'; import numeral from '@elastic/numeral'; +import { ElasticsearchClient } from 'kibana/server'; import { BaseAlert } from './base_alert'; import { AlertData, @@ -68,7 +69,7 @@ export class MemoryUsageAlert extends BaseAlert { protected async fetchData( params: CommonAlertParams, - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], availableCcs: string[] ): Promise { @@ -82,7 +83,7 @@ export class MemoryUsageAlert extends BaseAlert { const startMs = endMs - parsedDuration; const stats = await fetchMemoryUsageNodeStats( - callCluster, + esClient, clusters, esIndexPattern, startMs, diff --git a/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_alert.test.ts b/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_alert.test.ts index 28085f8b5e388..87790ee111326 100644 --- a/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_alert.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_alert.test.ts @@ -9,6 +9,7 @@ import { MissingMonitoringDataAlert } from './missing_monitoring_data_alert'; import { ALERT_MISSING_MONITORING_DATA } from '../../common/constants'; import { fetchMissingMonitoringData } from '../lib/alerts/fetch_missing_monitoring_data'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; const RealDate = Date; @@ -87,7 +88,7 @@ describe('MissingMonitoringDataAlert', () => { const getState = jest.fn(); const executorOptions = { services: { - callCluster: jest.fn(), + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), alertInstanceFactory: jest.fn().mockImplementation(() => { return { replaceState, diff --git a/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_alert.ts b/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_alert.ts index adf10e4e56dbc..ed35f775b249c 100644 --- a/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/missing_monitoring_data_alert.ts @@ -7,6 +7,7 @@ import { i18n } from '@kbn/i18n'; import moment from 'moment'; +import { ElasticsearchClient } from 'kibana/server'; import { BaseAlert } from './base_alert'; import { AlertData, @@ -66,7 +67,7 @@ export class MissingMonitoringDataAlert extends BaseAlert { } protected async fetchData( params: CommonAlertParams, - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], availableCcs: string[] ): Promise { @@ -78,7 +79,7 @@ export class MissingMonitoringDataAlert extends BaseAlert { const limit = parseDuration(params.limit!); const now = +new Date(); const missingData = await fetchMissingMonitoringData( - callCluster, + esClient, clusters, indexPattern, Globals.app.config.ui.max_bucket_size, diff --git a/x-pack/plugins/monitoring/server/alerts/nodes_changed_alert.test.ts b/x-pack/plugins/monitoring/server/alerts/nodes_changed_alert.test.ts index 848436573fab9..fa97de364d792 100644 --- a/x-pack/plugins/monitoring/server/alerts/nodes_changed_alert.test.ts +++ b/x-pack/plugins/monitoring/server/alerts/nodes_changed_alert.test.ts @@ -9,6 +9,7 @@ import { NodesChangedAlert } from './nodes_changed_alert'; import { ALERT_NODES_CHANGED } from '../../common/constants'; import { fetchNodesFromClusterStats } from '../lib/alerts/fetch_nodes_from_cluster_stats'; import { fetchClusters } from '../lib/alerts/fetch_clusters'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; const RealDate = Date; @@ -106,7 +107,7 @@ describe('NodesChangedAlert', () => { const getState = jest.fn(); const executorOptions = { services: { - callCluster: jest.fn(), + scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(), alertInstanceFactory: jest.fn().mockImplementation(() => { return { replaceState, diff --git a/x-pack/plugins/monitoring/server/alerts/nodes_changed_alert.ts b/x-pack/plugins/monitoring/server/alerts/nodes_changed_alert.ts index d040ce1a890ae..b26008ff3860d 100644 --- a/x-pack/plugins/monitoring/server/alerts/nodes_changed_alert.ts +++ b/x-pack/plugins/monitoring/server/alerts/nodes_changed_alert.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { ElasticsearchClient } from 'kibana/server'; import { BaseAlert } from './base_alert'; import { AlertData, @@ -102,7 +103,7 @@ export class NodesChangedAlert extends BaseAlert { protected async fetchData( params: CommonAlertParams, - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], availableCcs: string[] ): Promise { @@ -111,7 +112,7 @@ export class NodesChangedAlert extends BaseAlert { esIndexPattern = getCcsIndexPattern(esIndexPattern, availableCcs); } const nodesFromClusterStats = await fetchNodesFromClusterStats( - callCluster, + esClient, clusters, esIndexPattern ); diff --git a/x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_alert_base.ts b/x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_alert_base.ts index cee319504e461..bb91418fc2090 100644 --- a/x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_alert_base.ts +++ b/x-pack/plugins/monitoring/server/alerts/thread_pool_rejections_alert_base.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { ElasticsearchClient } from 'kibana/server'; import { BaseAlert } from './base_alert'; import { AlertData, @@ -66,7 +67,7 @@ export class ThreadPoolRejectionsAlertBase extends BaseAlert { protected async fetchData( params: ThreadPoolRejectionsAlertParams, - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], availableCcs: string[] ): Promise { @@ -78,7 +79,7 @@ export class ThreadPoolRejectionsAlertBase extends BaseAlert { const { threshold, duration } = params; const stats = await fetchThreadPoolRejectionStats( - callCluster, + esClient, clusters, esIndexPattern, Globals.app.config.ui.max_bucket_size, diff --git a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_usage_collector.test.ts b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_usage_collector.test.ts index e1a93dec8aaee..03a3659b49ce1 100644 --- a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_usage_collector.test.ts +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_usage_collector.test.ts @@ -6,11 +6,11 @@ */ import { getMonitoringUsageCollector } from './get_usage_collector'; -import { fetchClusters } from '../../lib/alerts/fetch_clusters'; +import { fetchClustersLegacy } from '../../lib/alerts/fetch_clusters'; import { elasticsearchServiceMock } from '../../../../../../src/core/server/mocks'; jest.mock('../../lib/alerts/fetch_clusters', () => ({ - fetchClusters: jest.fn().mockImplementation(() => { + fetchClustersLegacy: jest.fn().mockImplementation(() => { return [ { clusterUuid: '1abc', @@ -153,7 +153,7 @@ describe('getMonitoringUsageCollector', () => { const mock = (usageCollection.makeUsageCollector as jest.Mock).mock; const args = mock.calls[0]; - (fetchClusters as jest.Mock).mockImplementation(() => { + (fetchClustersLegacy as jest.Mock).mockImplementation(() => { return []; }); @@ -173,7 +173,7 @@ describe('getMonitoringUsageCollector', () => { const mock = (usageCollection.makeUsageCollector as jest.Mock).mock; const args = mock.calls[0]; - (fetchClusters as jest.Mock).mockImplementation(() => { + (fetchClustersLegacy as jest.Mock).mockImplementation(() => { return []; }); diff --git a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_usage_collector.ts b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_usage_collector.ts index 1ea7b9b8ac407..6f638b6ff8f0e 100644 --- a/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_usage_collector.ts +++ b/x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_usage_collector.ts @@ -8,13 +8,13 @@ import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { ILegacyClusterClient } from 'src/core/server'; import { MonitoringConfig } from '../../config'; -import { fetchAvailableCcs } from '../../lib/alerts/fetch_available_ccs'; +import { fetchAvailableCcsLegacy } from '../../lib/alerts/fetch_available_ccs'; import { getStackProductsUsage } from './lib/get_stack_products_usage'; import { fetchLicenseType } from './lib/fetch_license_type'; import { MonitoringUsage, StackProductUsage, MonitoringClusterStackProductUsage } from './types'; import { INDEX_PATTERN_ELASTICSEARCH } from '../../../common/constants'; import { getCcsIndexPattern } from '../../lib/alerts/get_ccs_index_pattern'; -import { fetchClusters } from '../../lib/alerts/fetch_clusters'; +import { fetchClustersLegacy } from '../../lib/alerts/fetch_clusters'; export function getMonitoringUsageCollector( usageCollection: UsageCollectionSetup, @@ -106,9 +106,9 @@ export function getMonitoringUsageCollector( ? legacyEsClient.asScoped(kibanaRequest).callAsCurrentUser : legacyEsClient.callAsInternalUser; const usageClusters: MonitoringClusterStackProductUsage[] = []; - const availableCcs = config.ui.ccs.enabled ? await fetchAvailableCcs(callCluster) : []; + const availableCcs = config.ui.ccs.enabled ? await fetchAvailableCcsLegacy(callCluster) : []; const elasticsearchIndex = getCcsIndexPattern(INDEX_PATTERN_ELASTICSEARCH, availableCcs); - const clusters = await fetchClusters(callCluster, elasticsearchIndex); + const clusters = await fetchClustersLegacy(callCluster, elasticsearchIndex); for (const cluster of clusters) { const license = await fetchLicenseType(callCluster, availableCcs, cluster.clusterUuid); const stackProducts = await getStackProductsUsage( diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.test.ts index 20eea1b5ed8e1..ecfb5fc50a16d 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.test.ts @@ -5,34 +5,46 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { fetchAvailableCcs } from './fetch_available_ccs'; describe('fetchAvailableCcs', () => { it('should call the `cluster.remoteInfo` api', async () => { - const callCluster = jest.fn(); - await fetchAvailableCcs(callCluster); - expect(callCluster).toHaveBeenCalledWith('cluster.remoteInfo'); + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + + await fetchAvailableCcs(esClient); + expect(esClient.cluster.remoteInfo).toHaveBeenCalled(); }); it('should return clusters that are connected', async () => { const connectedRemote = 'myRemote'; - const callCluster = jest.fn().mockImplementation(() => ({ - [connectedRemote]: { - connected: true, - }, - })); - const result = await fetchAvailableCcs(callCluster); + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + esClient.cluster.remoteInfo.mockImplementation(() => + elasticsearchClientMock.createSuccessTransportRequestPromise({ + [connectedRemote]: { + connected: true, + }, + }) + ); + + const result = await fetchAvailableCcs(esClient); expect(result).toEqual([connectedRemote]); }); it('should not return clusters that are connected', async () => { const disconnectedRemote = 'myRemote'; - const callCluster = jest.fn().mockImplementation(() => ({ - [disconnectedRemote]: { - connected: false, - }, - })); - const result = await fetchAvailableCcs(callCluster); + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + esClient.cluster.remoteInfo.mockImplementation(() => + elasticsearchClientMock.createSuccessTransportRequestPromise({ + [disconnectedRemote]: { + connected: false, + }, + }) + ); + + const result = await fetchAvailableCcs(esClient); expect(result.length).toBe(0); }); }); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.ts index 10bc2ead2cb11..0dd0def028e36 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_available_ccs.ts @@ -5,7 +5,24 @@ * 2.0. */ -export async function fetchAvailableCcs(callCluster: any): Promise { +import { ElasticsearchClient } from 'kibana/server'; + +export async function fetchAvailableCcs(esClient: ElasticsearchClient): Promise { + const availableCcs = []; + const { body: response } = await esClient.cluster.remoteInfo(); + for (const remoteName in response) { + if (!response.hasOwnProperty(remoteName)) { + continue; + } + const remoteInfo = response[remoteName]; + if (remoteInfo.connected) { + availableCcs.push(remoteName); + } + } + return availableCcs; +} + +export async function fetchAvailableCcsLegacy(callCluster: any): Promise { const availableCcs = []; const response = await callCluster('cluster.remoteInfo'); for (const remoteName in response) { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts index 8aede7a73e61d..330be4e90ed56 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts @@ -5,11 +5,12 @@ * 2.0. */ +import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { CCRReadExceptionsStats } from '../../../common/types/alerts'; export async function fetchCCRReadExceptions( - callCluster: any, + esClient: ElasticsearchClient, index: string, startMs: number, endMs: number, @@ -92,7 +93,7 @@ export async function fetchCCRReadExceptions( }, }; - const response = await callCluster('search', params); + const { body: response } = await esClient.search(params); const stats: CCRReadExceptionsStats[] = []; const { buckets: remoteClusterBuckets = [] } = response.aggregations.remote_clusters; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts index 2fdbbe80b7e89..d326c7f4bedda 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.test.ts @@ -5,32 +5,37 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; import { fetchClusterHealth } from './fetch_cluster_health'; describe('fetchClusterHealth', () => { it('should return the cluster health', async () => { const status = 'green'; const clusterUuid = 'sdfdsaj34434'; - const callCluster = jest.fn(() => ({ - hits: { - hits: [ - { - _index: '.monitoring-es-7', - _source: { - cluster_state: { - status, + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + hits: [ + { + _index: '.monitoring-es-7', + _source: { + cluster_state: { + status, + }, + cluster_uuid: clusterUuid, }, - cluster_uuid: clusterUuid, }, - }, - ], - }, - })); + ], + }, + }) + ); const clusters = [{ clusterUuid, clusterName: 'foo' }]; const index = '.monitoring-es-*'; - const health = await fetchClusterHealth(callCluster, clusters, index); + const health = await fetchClusterHealth(esClient, clusters, index); expect(health).toEqual([ { health: status, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts index bcfa2da0958a2..be91aaa6ec983 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts @@ -4,11 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { ElasticsearchClient } from 'kibana/server'; import { AlertCluster, AlertClusterHealth } from '../../../common/types/alerts'; import { ElasticsearchSource } from '../../../common/types/es'; export async function fetchClusterHealth( - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], index: string ): Promise { @@ -58,7 +59,7 @@ export async function fetchClusterHealth( }, }; - const response = await callCluster('search', params); + const { body: response } = await esClient.search(params); return response.hits.hits.map((hit: { _source: ElasticsearchSource; _index: string }) => { return { health: hit._source.cluster_state?.status, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts index 7a1d0acd73b12..54aa2e68d4ef2 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.test.ts @@ -5,6 +5,9 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { fetchClusters } from './fetch_clusters'; describe('fetchClusters', () => { @@ -12,54 +15,60 @@ describe('fetchClusters', () => { const clusterName = 'monitoring'; it('return a list of clusters', async () => { - const callCluster = jest.fn().mockImplementation(() => ({ - hits: { - hits: [ - { - _source: { - cluster_uuid: clusterUuid, - cluster_name: clusterName, + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + hits: [ + { + _source: { + cluster_uuid: clusterUuid, + cluster_name: clusterName, + }, }, - }, - ], - }, - })); + ], + }, + }) + ); const index = '.monitoring-es-*'; - const result = await fetchClusters(callCluster, index); + const result = await fetchClusters(esClient, index); expect(result).toEqual([{ clusterUuid, clusterName }]); }); it('return the metadata name if available', async () => { const metadataName = 'custom-monitoring'; - const callCluster = jest.fn().mockImplementation(() => ({ - hits: { - hits: [ - { - _source: { - cluster_uuid: clusterUuid, - cluster_name: clusterName, - cluster_settings: { - cluster: { - metadata: { - display_name: metadataName, + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + hits: [ + { + _source: { + cluster_uuid: clusterUuid, + cluster_name: clusterName, + cluster_settings: { + cluster: { + metadata: { + display_name: metadataName, + }, }, }, }, }, - }, - ], - }, - })); + ], + }, + }) + ); const index = '.monitoring-es-*'; - const result = await fetchClusters(callCluster, index); + const result = await fetchClusters(esClient, index); expect(result).toEqual([{ clusterUuid, clusterName: metadataName }]); }); it('should limit the time period in the query', async () => { - const callCluster = jest.fn(); + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; const index = '.monitoring-es-*'; - await fetchClusters(callCluster, index); - const params = callCluster.mock.calls[0][1]; - expect(params.body.query.bool.filter[1].range.timestamp.gte).toBe('now-2m'); + await fetchClusters(esClient, index); + const params = esClient.search.mock.calls[0][0] as any; + expect(params?.body?.query.bool.filter[1].range.timestamp.gte).toBe('now-2m'); }); }); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts index 871370977bb38..bbaea8d9f206e 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { AlertCluster } from '../../../common/types/alerts'; @@ -16,7 +17,7 @@ interface RangeFilter { } export async function fetchClusters( - callCluster: any, + esClient: ElasticsearchClient, index: string, rangeFilter: RangeFilter = { timestamp: { gte: 'now-2m' } } ): Promise { @@ -49,6 +50,52 @@ export async function fetchClusters( }, }; + const { body: response } = await esClient.search(params); + return get(response, 'hits.hits', []).map((hit: any) => { + const clusterName: string = + get(hit, '_source.cluster_settings.cluster.metadata.display_name') || + get(hit, '_source.cluster_name') || + get(hit, '_source.cluster_uuid'); + return { + clusterUuid: get(hit, '_source.cluster_uuid'), + clusterName, + }; + }); +} + +export async function fetchClustersLegacy( + callCluster: any, + index: string, + rangeFilter: RangeFilter = { timestamp: { gte: 'now-2m' } } +): Promise { + const params = { + index, + filterPath: [ + 'hits.hits._source.cluster_settings.cluster.metadata.display_name', + 'hits.hits._source.cluster_uuid', + 'hits.hits._source.cluster_name', + ], + body: { + size: 1000, + query: { + bool: { + filter: [ + { + term: { + type: 'cluster_stats', + }, + }, + { + range: rangeFilter, + }, + ], + }, + }, + collapse: { + field: 'cluster_uuid', + }, + }, + }; const response = await callCluster('search', params); return get(response, 'hits.hits', []).map((hit: any) => { const clusterName: string = diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts index 0f66217180133..2ff9ae3854e4a 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.test.ts @@ -5,10 +5,12 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; import { fetchCpuUsageNodeStats } from './fetch_cpu_usage_node_stats'; describe('fetchCpuUsageNodeStats', () => { - let callCluster = jest.fn(); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; const clusters = [ { clusterUuid: 'abc123', @@ -21,8 +23,8 @@ describe('fetchCpuUsageNodeStats', () => { const size = 10; it('fetch normal stats', async () => { - callCluster = jest.fn().mockImplementation((...args) => { - return { + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ aggregations: { clusters: { buckets: [ @@ -56,9 +58,9 @@ describe('fetchCpuUsageNodeStats', () => { ], }, }, - }; - }); - const result = await fetchCpuUsageNodeStats(callCluster, clusters, index, startMs, endMs, size); + }) + ); + const result = await fetchCpuUsageNodeStats(esClient, clusters, index, startMs, endMs, size); expect(result).toEqual([ { clusterUuid: clusters[0].clusterUuid, @@ -74,8 +76,8 @@ describe('fetchCpuUsageNodeStats', () => { }); it('fetch container stats', async () => { - callCluster = jest.fn().mockImplementation((...args) => { - return { + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ aggregations: { clusters: { buckets: [ @@ -122,9 +124,9 @@ describe('fetchCpuUsageNodeStats', () => { ], }, }, - }; - }); - const result = await fetchCpuUsageNodeStats(callCluster, clusters, index, startMs, endMs, size); + }) + ); + const result = await fetchCpuUsageNodeStats(esClient, clusters, index, startMs, endMs, size); expect(result).toEqual([ { clusterUuid: clusters[0].clusterUuid, @@ -140,8 +142,8 @@ describe('fetchCpuUsageNodeStats', () => { }); it('fetch properly return ccs', async () => { - callCluster = jest.fn().mockImplementation((...args) => { - return { + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ aggregations: { clusters: { buckets: [ @@ -181,18 +183,19 @@ describe('fetchCpuUsageNodeStats', () => { ], }, }, - }; - }); - const result = await fetchCpuUsageNodeStats(callCluster, clusters, index, startMs, endMs, size); + }) + ); + const result = await fetchCpuUsageNodeStats(esClient, clusters, index, startMs, endMs, size); expect(result[0].ccs).toBe('foo'); }); it('should use consistent params', async () => { let params = null; - callCluster = jest.fn().mockImplementation((...args) => { - params = args[1]; + esClient.search.mockImplementation((...args) => { + params = args[0]; + return elasticsearchClientMock.createSuccessTransportRequestPromise({}); }); - await fetchCpuUsageNodeStats(callCluster, clusters, index, startMs, endMs, size); + await fetchCpuUsageNodeStats(esClient, clusters, index, startMs, endMs, size); expect(params).toStrictEqual({ index: '.monitoring-es-*', filterPath: ['aggregations'], diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts index dc8e5fc52eadf..1dfbe381b9956 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import moment from 'moment'; import { NORMALIZED_DERIVATIVE_UNIT } from '../../../common/constants'; @@ -23,7 +24,7 @@ interface ClusterBucketESResponse { } export async function fetchCpuUsageNodeStats( - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], index: string, startMs: number, @@ -140,7 +141,7 @@ export async function fetchCpuUsageNodeStats( }, }; - const response = await callCluster('search', params); + const { body: response } = await esClient.search(params); const stats: AlertCpuUsageNodeStats[] = []; const clusterBuckets = get( response, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.test.ts index 56b599f73b939..7664d73f6009b 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.test.ts @@ -5,10 +5,14 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { fetchDiskUsageNodeStats } from './fetch_disk_usage_node_stats'; describe('fetchDiskUsageNodeStats', () => { - let callCluster = jest.fn(); + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + const clusters = [ { clusterUuid: 'cluster123', @@ -20,8 +24,8 @@ describe('fetchDiskUsageNodeStats', () => { const size = 10; it('fetch normal stats', async () => { - callCluster = jest.fn().mockImplementation(() => { - return { + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ aggregations: { clusters: { buckets: [ @@ -55,10 +59,10 @@ describe('fetchDiskUsageNodeStats', () => { ], }, }, - }; - }); + }) + ); - const result = await fetchDiskUsageNodeStats(callCluster, clusters, index, duration, size); + const result = await fetchDiskUsageNodeStats(esClient, clusters, index, duration, size); expect(result).toEqual([ { clusterUuid: clusters[0].clusterUuid, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts index 912fab19951df..aea4ede825d67 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts @@ -5,11 +5,12 @@ * 2.0. */ +import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { AlertCluster, AlertDiskUsageNodeStats } from '../../../common/types/alerts'; export async function fetchDiskUsageNodeStats( - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], index: string, duration: string, @@ -98,7 +99,7 @@ export async function fetchDiskUsageNodeStats( }, }; - const response = await callCluster('search', params); + const { body: response } = await esClient.search(params); const stats: AlertDiskUsageNodeStats[] = []; const { buckets: clusterBuckets = [] } = response.aggregations.clusters; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts index e4f4a4d364ebf..be501ee3d5280 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.test.ts @@ -5,10 +5,14 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { fetchElasticsearchVersions } from './fetch_elasticsearch_versions'; describe('fetchElasticsearchVersions', () => { - let callCluster = jest.fn(); + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + const clusters = [ { clusterUuid: 'cluster123', @@ -20,8 +24,8 @@ describe('fetchElasticsearchVersions', () => { const versions = ['8.0.0', '7.2.1']; it('fetch as expected', async () => { - callCluster = jest.fn().mockImplementation(() => { - return { + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ hits: { hits: [ { @@ -37,10 +41,10 @@ describe('fetchElasticsearchVersions', () => { }, ], }, - }; - }); + }) + ); - const result = await fetchElasticsearchVersions(callCluster, clusters, index, size); + const result = await fetchElasticsearchVersions(esClient, clusters, index, size); expect(result).toEqual([ { clusterUuid: clusters[0].clusterUuid, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts index 373ddb62aaee8..b4b7739f6731b 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts @@ -4,11 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { ElasticsearchClient } from 'kibana/server'; import { AlertCluster, AlertVersions } from '../../../common/types/alerts'; import { ElasticsearchSource } from '../../../common/types/es'; export async function fetchElasticsearchVersions( - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], index: string, size: number @@ -59,7 +60,7 @@ export async function fetchElasticsearchVersions( }, }; - const response = await callCluster('search', params); + const { body: response } = await esClient.search(params); return response.hits.hits.map((hit: { _source: ElasticsearchSource; _index: string }) => { const versions = hit._source.cluster_stats?.nodes?.versions; return { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts index 63c2910c46e5d..dfba0c42eef3d 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { ElasticsearchClient } from 'kibana/server'; import { AlertCluster, IndexShardSizeStats } from '../../../common/types/alerts'; import { ElasticsearchIndexStats, ElasticsearchResponseHit } from '../../../common/types/es'; import { ESGlobPatterns, RegExPatterns } from '../../../common/es_glob_patterns'; @@ -29,7 +30,7 @@ const memoizedIndexPatterns = (globPatterns: string) => { const gbMultiplier = 1000000000; export async function fetchIndexShardSize( - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], index: string, threshold: number, @@ -113,7 +114,7 @@ export async function fetchIndexShardSize( }, }; - const response = await callCluster('search', params); + const { body: response } = await esClient.search(params); const stats: IndexShardSizeStats[] = []; const { buckets: clusterBuckets = [] } = response.aggregations.clusters; const validIndexPatterns = memoizedIndexPatterns(shardIndexPatterns); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.test.ts index 518828ef0b1c8..901851d766512 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.test.ts @@ -6,9 +6,12 @@ */ import { fetchKibanaVersions } from './fetch_kibana_versions'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; describe('fetchKibanaVersions', () => { - let callCluster = jest.fn(); + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; const clusters = [ { clusterUuid: 'cluster123', @@ -19,8 +22,8 @@ describe('fetchKibanaVersions', () => { const size = 10; it('fetch as expected', async () => { - callCluster = jest.fn().mockImplementation(() => { - return { + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ aggregations: { index: { buckets: [ @@ -59,10 +62,10 @@ describe('fetchKibanaVersions', () => { ], }, }, - }; - }); + }) + ); - const result = await fetchKibanaVersions(callCluster, clusters, index, size); + const result = await fetchKibanaVersions(esClient, clusters, index, size); expect(result).toEqual([ { clusterUuid: clusters[0].clusterUuid, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts index 2e7fe192df656..a4e1e606702ec 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { AlertCluster, AlertVersions } from '../../../common/types/alerts'; @@ -12,7 +13,7 @@ interface ESAggResponse { } export async function fetchKibanaVersions( - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], index: string, size: number @@ -88,7 +89,7 @@ export async function fetchKibanaVersions( }, }; - const response = await callCluster('search', params); + const { body: response } = await esClient.search(params); const indexName = get(response, 'aggregations.index.buckets[0].key', ''); const clusterList = get(response, 'aggregations.cluster.buckets', []) as ESAggResponse[]; return clusterList.map((cluster) => { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts index 715c8c50a45e7..69a42812bfe88 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.test.ts @@ -5,6 +5,9 @@ * 2.0. */ import { fetchLicenses } from './fetch_licenses'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; describe('fetchLicenses', () => { const clusterName = 'MyCluster'; @@ -16,21 +19,24 @@ describe('fetchLicenses', () => { }; it('return a list of licenses', async () => { - const callCluster = jest.fn().mockImplementation(() => ({ - hits: { - hits: [ - { - _source: { - license, - cluster_uuid: clusterUuid, + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + hits: [ + { + _source: { + license, + cluster_uuid: clusterUuid, + }, }, - }, - ], - }, - })); + ], + }, + }) + ); const clusters = [{ clusterUuid, clusterName }]; const index = '.monitoring-es-*'; - const result = await fetchLicenses(callCluster, clusters, index); + const result = await fetchLicenses(esClient, clusters, index); expect(result).toEqual([ { status: license.status, @@ -42,20 +48,20 @@ describe('fetchLicenses', () => { }); it('should only search for the clusters provided', async () => { - const callCluster = jest.fn(); + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; const clusters = [{ clusterUuid, clusterName }]; const index = '.monitoring-es-*'; - await fetchLicenses(callCluster, clusters, index); - const params = callCluster.mock.calls[0][1]; - expect(params.body.query.bool.filter[0].terms.cluster_uuid).toEqual([clusterUuid]); + await fetchLicenses(esClient, clusters, index); + const params = esClient.search.mock.calls[0][0] as any; + expect(params?.body?.query.bool.filter[0].terms.cluster_uuid).toEqual([clusterUuid]); }); it('should limit the time period in the query', async () => { - const callCluster = jest.fn(); + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; const clusters = [{ clusterUuid, clusterName }]; const index = '.monitoring-es-*'; - await fetchLicenses(callCluster, clusters, index); - const params = callCluster.mock.calls[0][1]; - expect(params.body.query.bool.filter[2].range.timestamp.gte).toBe('now-2m'); + await fetchLicenses(esClient, clusters, index); + const params = esClient.search.mock.calls[0][0] as any; + expect(params?.body?.query.bool.filter[2].range.timestamp.gte).toBe('now-2m'); }); }); diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts index 6cec7f3296926..5cd4378f0a747 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts @@ -4,11 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { ElasticsearchClient } from 'kibana/server'; import { AlertLicense, AlertCluster } from '../../../common/types/alerts'; import { ElasticsearchResponse } from '../../../common/types/es'; export async function fetchLicenses( - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], index: string ): Promise { @@ -58,7 +59,7 @@ export async function fetchLicenses( }, }; - const response: ElasticsearchResponse = await callCluster('search', params); + const { body: response } = await esClient.search(params); return ( response?.hits?.hits.map((hit) => { const rawLicense = hit._source.license ?? {}; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.test.ts index a739593df27e9..e35de6e68866d 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.test.ts @@ -6,9 +6,12 @@ */ import { fetchLogstashVersions } from './fetch_logstash_versions'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; describe('fetchLogstashVersions', () => { - let callCluster = jest.fn(); + const esClient = elasticsearchServiceMock.createScopedClusterClient().asCurrentUser; const clusters = [ { clusterUuid: 'cluster123', @@ -19,8 +22,8 @@ describe('fetchLogstashVersions', () => { const size = 10; it('fetch as expected', async () => { - callCluster = jest.fn().mockImplementation(() => { - return { + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ aggregations: { index: { buckets: [ @@ -59,10 +62,10 @@ describe('fetchLogstashVersions', () => { ], }, }, - }; - }); + }) + ); - const result = await fetchLogstashVersions(callCluster, clusters, index, size); + const result = await fetchLogstashVersions(esClient, clusters, index, size); expect(result).toEqual([ { clusterUuid: clusters[0].clusterUuid, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts index 8f20c64d6243e..6090ba36d9749 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { AlertCluster, AlertVersions } from '../../../common/types/alerts'; @@ -12,7 +13,7 @@ interface ESAggResponse { } export async function fetchLogstashVersions( - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], index: string, size: number @@ -88,7 +89,7 @@ export async function fetchLogstashVersions( }, }; - const response = await callCluster('search', params); + const { body: response } = await esClient.search(params); const indexName = get(response, 'aggregations.index.buckets[0].key', ''); const clusterList = get(response, 'aggregations.cluster.buckets', []) as ESAggResponse[]; return clusterList.map((cluster) => { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts index 2b2af9572390e..77c17a8ebf3ef 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts @@ -5,11 +5,12 @@ * 2.0. */ +import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { AlertCluster, AlertMemoryUsageNodeStats } from '../../../common/types/alerts'; export async function fetchMemoryUsageNodeStats( - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], index: string, startMs: number, @@ -91,7 +92,7 @@ export async function fetchMemoryUsageNodeStats( }, }; - const response = await callCluster('search', params); + const { body: response } = await esClient.search(params); const stats: AlertMemoryUsageNodeStats[] = []; const { buckets: clusterBuckets = [] } = response.aggregations.clusters; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.test.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.test.ts index 4f907aa628c43..2388abf024eb9 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.test.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.test.ts @@ -5,6 +5,8 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; import { fetchMissingMonitoringData } from './fetch_missing_monitoring_data'; function getResponse( @@ -38,7 +40,8 @@ function getResponse( } describe('fetchMissingMonitoringData', () => { - let callCluster = jest.fn(); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + const index = '.monitoring-*'; const startMs = 100; const size = 10; @@ -51,8 +54,9 @@ describe('fetchMissingMonitoringData', () => { clusterName: 'clusterName1', }, ]; - callCluster = jest.fn().mockImplementation((...args) => { - return { + + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ aggregations: { clusters: { buckets: clusters.map((cluster) => ({ @@ -80,16 +84,9 @@ describe('fetchMissingMonitoringData', () => { })), }, }, - }; - }); - const result = await fetchMissingMonitoringData( - callCluster, - clusters, - index, - size, - now, - startMs + }) ); + const result = await fetchMissingMonitoringData(esClient, clusters, index, size, now, startMs); expect(result).toEqual([ { nodeId: 'nodeUuid1', @@ -116,8 +113,8 @@ describe('fetchMissingMonitoringData', () => { clusterName: 'clusterName1', }, ]; - callCluster = jest.fn().mockImplementation((...args) => { - return { + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ aggregations: { clusters: { buckets: clusters.map((cluster) => ({ @@ -136,16 +133,9 @@ describe('fetchMissingMonitoringData', () => { })), }, }, - }; - }); - const result = await fetchMissingMonitoringData( - callCluster, - clusters, - index, - size, - now, - startMs + }) ); + const result = await fetchMissingMonitoringData(esClient, clusters, index, size, now, startMs); expect(result).toEqual([ { nodeId: 'nodeUuid1', diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts index fa5f9c6620cf5..cb274848e6c5a 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { AlertCluster, AlertMissingData } from '../../../common/types/alerts'; @@ -41,7 +42,7 @@ interface TopHitESResponse { // TODO: only Elasticsearch until we can figure out how to handle upgrades for the rest of the stack // https://github.com/elastic/kibana/issues/83309 export async function fetchMissingMonitoringData( - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], index: string, size: number, @@ -116,7 +117,7 @@ export async function fetchMissingMonitoringData( }, }; - const response = await callCluster('search', params); + const { body: response } = await esClient.search(params); const clusterBuckets = get( response, 'aggregations.clusters.buckets', diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts index c399594c170fa..a97594c8ca995 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { ElasticsearchClient } from 'kibana/server'; import { AlertCluster, AlertClusterStatsNodes } from '../../../common/types/alerts'; import { ElasticsearchSource } from '../../../common/types/es'; @@ -23,7 +24,7 @@ function formatNode( } export async function fetchNodesFromClusterStats( - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], index: string ): Promise { @@ -87,7 +88,7 @@ export async function fetchNodesFromClusterStats( }, }; - const response = await callCluster('search', params); + const { body: response } = await esClient.search(params); const nodes = []; const clusterBuckets = response.aggregations.clusters.buckets; for (const clusterBucket of clusterBuckets) { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts index 80624b6d5233c..5770721195e14 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { ElasticsearchClient } from 'kibana/server'; import { get } from 'lodash'; import { AlertCluster, AlertThreadPoolRejectionsStats } from '../../../common/types/alerts'; @@ -30,7 +31,7 @@ const getTopHits = (threadType: string, order: string) => ({ }); export async function fetchThreadPoolRejectionStats( - callCluster: any, + esClient: ElasticsearchClient, clusters: AlertCluster[], index: string, size: number, @@ -93,7 +94,7 @@ export async function fetchThreadPoolRejectionStats( }, }; - const response = await callCluster('search', params); + const { body: response } = await esClient.search(params); const stats: AlertThreadPoolRejectionsStats[] = []; const { buckets: clusterBuckets = [] } = response.aggregations.clusters; diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/verify_alerting_security.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/verify_alerting_security.ts index facb6e29236e3..f5f9c80e0e4d3 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/verify_alerting_security.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/verify_alerting_security.ts @@ -34,13 +34,12 @@ export class AlertingSecurity { enabled: isSecurityEnabled = false, ssl: { http: { enabled: isTLSEnabled = false } = {} } = {}, } = {}, - }: XPackUsageSecurity = await context.core.elasticsearch.legacy.client.callAsInternalUser( - 'transport.request', - { + } = ( + await context.core.elasticsearch.client.asInternalUser.transport.request({ method: 'GET', path: '/_xpack/usage', - } - ); + }) + ).body as XPackUsageSecurity; return { isSufficientlySecure: !isSecurityEnabled || (isSecurityEnabled && isTLSEnabled), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/index/create_bootstrap_index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/index/create_bootstrap_index.ts index f66cf2e0e8ebb..fd9b63152ddd3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/index/create_bootstrap_index.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/index/create_bootstrap_index.ts @@ -5,24 +5,26 @@ * 2.0. */ -import { CallWithRequest } from '../types'; +import { ElasticsearchClient } from 'kibana/server'; // See the reference(s) below on explanations about why -000001 was chosen and // why the is_write_index is true as well as the bootstrapping step which is needed. // Ref: https://www.elastic.co/guide/en/elasticsearch/reference/current/applying-policy-to-template.html export const createBootstrapIndex = async ( - callWithRequest: CallWithRequest<{ path: string; method: 'PUT'; body: unknown }, boolean>, + esClient: ElasticsearchClient, index: string ): Promise => { - return callWithRequest('transport.request', { - path: `/${index}-000001`, - method: 'PUT', - body: { - aliases: { - [index]: { - is_write_index: true, + return ( + await esClient.transport.request({ + path: `/${index}-000001`, + method: 'PUT', + body: { + aliases: { + [index]: { + is_write_index: true, + }, }, }, - }, - }); + }) + ).body; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/index/delete_all_index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/index/delete_all_index.ts index b70ead2b05aff..98a8f8c28d30d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/index/delete_all_index.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/index/delete_all_index.ts @@ -5,11 +5,10 @@ * 2.0. */ -import { IndicesDeleteParams, Client } from 'elasticsearch'; -import { CallWithRequest } from '../types'; +import { ElasticsearchClient } from 'kibana/server'; export const deleteAllIndex = async ( - callWithRequest: CallWithRequest>, + esClient: ElasticsearchClient, pattern: string, maxAttempts = 5 ): Promise => { @@ -21,10 +20,12 @@ export const deleteAllIndex = async ( } // resolve pattern to concrete index names - const resp = await callWithRequest('indices.getAlias', { - index: pattern, - ignore: 404, - }); + const { body: resp } = await esClient.indices.getAlias( + { + index: pattern, + }, + { ignore: [404] } + ); if (resp.status === 404) { return true; @@ -38,9 +39,9 @@ export const deleteAllIndex = async ( } // delete the concrete indexes we found and try again until this pattern resolves to no indexes - await callWithRequest('indices.delete', { + await esClient.indices.delete({ index: indices, - ignoreUnavailable: true, + ignore_unavailable: true, }); } }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/index/delete_policy.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/index/delete_policy.ts index 63f8648b8e516..d671d256f56aa 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/index/delete_policy.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/index/delete_policy.ts @@ -5,14 +5,16 @@ * 2.0. */ -import { CallWithRequest } from '../types'; +import { ElasticsearchClient } from 'kibana/server'; export const deletePolicy = async ( - callWithRequest: CallWithRequest<{ path: string; method: 'DELETE' }, unknown>, + esClient: ElasticsearchClient, policy: string ): Promise => { - return callWithRequest('transport.request', { - path: `/_ilm/policy/${policy}`, - method: 'DELETE', - }); + return ( + await esClient.transport.request({ + path: `/_ilm/policy/${policy}`, + method: 'DELETE', + }) + ).body; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/index/delete_template.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/index/delete_template.ts index 3d9554a826172..e57bbd77120f2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/index/delete_template.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/index/delete_template.ts @@ -4,15 +4,15 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import { IndicesDeleteTemplateParams } from 'elasticsearch'; -import { CallWithRequest } from '../types'; +import { ElasticsearchClient } from 'kibana/server'; export const deleteTemplate = async ( - callWithRequest: CallWithRequest, + esClient: ElasticsearchClient, name: string ): Promise => { - return callWithRequest('indices.deleteTemplate', { - name, - }); + return ( + await esClient.indices.deleteTemplate({ + name, + }) + ).body; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_index_exists.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_index_exists.test.ts index a162dece4f13d..488ba0dab0b97 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_index_exists.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_index_exists.test.ts @@ -5,6 +5,8 @@ * 2.0. */ +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; import { getIndexExists } from './get_index_exists'; class StatusCode extends Error { @@ -17,29 +19,41 @@ class StatusCode extends Error { describe('get_index_exists', () => { test('it should return a true if you have _shards', async () => { - const callWithRequest = jest.fn().mockResolvedValue({ _shards: { total: 1 } }); - const indexExists = await getIndexExists(callWithRequest, 'some-index'); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 1 } }) + ); + const indexExists = await getIndexExists(esClient, 'some-index'); expect(indexExists).toEqual(true); }); test('it should return a false if you do NOT have _shards', async () => { - const callWithRequest = jest.fn().mockResolvedValue({ _shards: { total: 0 } }); - const indexExists = await getIndexExists(callWithRequest, 'some-index'); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 0 } }) + ); + const indexExists = await getIndexExists(esClient, 'some-index'); expect(indexExists).toEqual(false); }); test('it should return a false if it encounters a 404', async () => { - const callWithRequest = jest.fn().mockImplementation(() => { - throw new StatusCode(404, 'I am a 404 error'); - }); - const indexExists = await getIndexExists(callWithRequest, 'some-index'); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createErrorTransportRequestPromise({ + body: new StatusCode(404, 'I am a 404 error'), + }) + ); + const indexExists = await getIndexExists(esClient, 'some-index'); expect(indexExists).toEqual(false); }); test('it should reject if it encounters a non 404', async () => { - const callWithRequest = jest.fn().mockImplementation(() => { - throw new StatusCode(500, 'I am a 500 error'); - }); - await expect(getIndexExists(callWithRequest, 'some-index')).rejects.toThrow('I am a 500 error'); + const esClient = elasticsearchClientMock.createScopedClusterClient().asCurrentUser; + esClient.search.mockReturnValue( + elasticsearchClientMock.createErrorTransportRequestPromise( + new StatusCode(500, 'I am a 500 error') + ) + ); + await expect(getIndexExists(esClient, 'some-index')).rejects.toThrow('I am a 500 error'); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_index_exists.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_index_exists.ts index 4e9eb1a80566f..b86b58897ee62 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_index_exists.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_index_exists.ts @@ -5,17 +5,14 @@ * 2.0. */ -import { CallWithRequest } from '../types'; +import { ElasticsearchClient } from 'kibana/server'; export const getIndexExists = async ( - callWithRequest: CallWithRequest< - { index: string; size: number; terminate_after: number; allow_no_indices: boolean }, - { _shards: { total: number } } - >, + esClient: ElasticsearchClient, index: string ): Promise => { try { - const response = await callWithRequest('search', { + const { body: response } = await esClient.search({ index, size: 0, terminate_after: 1, @@ -23,10 +20,10 @@ export const getIndexExists = async ( }); return response._shards.total > 0; } catch (err) { - if (err.status === 404) { + if (err.body?.status === 404) { return false; } else { - throw err; + throw err.body ? err.body : err; } } }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_policy_exists.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_policy_exists.ts index 75118eb5062f3..c0d7c38a4bb02 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_policy_exists.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_policy_exists.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { CallWithRequest } from '../types'; +import { ElasticsearchClient } from 'kibana/server'; export const getPolicyExists = async ( - callWithRequest: CallWithRequest<{ path: string; method: 'GET' }, unknown>, + esClient: ElasticsearchClient, policy: string ): Promise => { try { - await callWithRequest('transport.request', { + await esClient.transport.request({ path: `/_ilm/policy/${policy}`, method: 'GET', }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_template_exists.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_template_exists.ts index 7237a5ce58e01..50ec3bfc670d5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_template_exists.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/index/get_template_exists.ts @@ -5,14 +5,15 @@ * 2.0. */ -import { IndicesExistsTemplateParams } from 'elasticsearch'; -import { CallWithRequest } from '../types'; +import { ElasticsearchClient } from 'kibana/server'; export const getTemplateExists = async ( - callWithRequest: CallWithRequest, + esClient: ElasticsearchClient, template: string ): Promise => { - return callWithRequest('indices.existsTemplate', { - name: template, - }); + return ( + await esClient.indices.existsTemplate({ + name: template, + }) + ).body; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/index/read_index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/index/read_index.ts index 653c9a2379cc2..7674ca3b48304 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/index/read_index.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/index/read_index.ts @@ -5,14 +5,10 @@ * 2.0. */ -import { IndicesGetSettingsParams } from 'elasticsearch'; -import { CallWithRequest } from '../types'; +import { ElasticsearchClient } from 'kibana/server'; -export const readIndex = async ( - callWithRequest: CallWithRequest, - index: string -): Promise => { - return callWithRequest('indices.get', { +export const readIndex = async (esClient: ElasticsearchClient, index: string): Promise => { + return esClient.indices.get({ index, }); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/index/set_policy.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/index/set_policy.ts index 1071551170c68..9dbcdd795ac71 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/index/set_policy.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/index/set_policy.ts @@ -5,16 +5,18 @@ * 2.0. */ -import { CallWithRequest } from '../types'; +import { ElasticsearchClient } from 'kibana/server'; export const setPolicy = async ( - callWithRequest: CallWithRequest<{ path: string; method: 'PUT'; body: unknown }, unknown>, + esClient: ElasticsearchClient, policy: string, - body: unknown + body: Record ): Promise => { - return callWithRequest('transport.request', { - path: `/_ilm/policy/${policy}`, - method: 'PUT', - body, - }); + return ( + await esClient.transport.request({ + path: `/_ilm/policy/${policy}`, + method: 'PUT', + body, + }) + ).body; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/index/set_template.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/index/set_template.ts index 11c240fce2356..e63dbbd6c3e8f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/index/set_template.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/index/set_template.ts @@ -5,16 +5,17 @@ * 2.0. */ -import { IndicesPutTemplateParams } from 'elasticsearch'; -import { CallWithRequest } from '../types'; +import { ElasticsearchClient } from 'kibana/server'; export const setTemplate = async ( - callWithRequest: CallWithRequest, + esClient: ElasticsearchClient, name: string, - body: unknown + body: Record ): Promise => { - return callWithRequest('indices.putTemplate', { - name, - body, - }); + return ( + await esClient.indices.putTemplate({ + name, + body, + }) + ).body; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/get_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/get_signals.ts index b716771d20ac3..b411ac2c69ef2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/get_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/get_signals.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AlertServices } from '../../../../../alerting/server'; +import { ElasticsearchClient } from 'kibana/server'; import { SignalSearchResponse } from '../signals/types'; import { buildSignalsSearchQuery } from './build_signals_query'; @@ -15,7 +15,7 @@ interface GetSignalsParams { size?: number; ruleId: string; index: string; - callCluster: AlertServices['callCluster']; + esClient: ElasticsearchClient; } export const getSignals = async ({ @@ -24,7 +24,7 @@ export const getSignals = async ({ size, ruleId, index, - callCluster, + esClient, }: GetSignalsParams): Promise => { if (from == null || to == null) { throw Error('"from" or "to" was not provided to signals query'); @@ -38,7 +38,7 @@ export const getSignals = async ({ size, }); - const result: SignalSearchResponse = await callCluster('search', query); + const { body: result } = await esClient.search(query); return result; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/get_signals_count.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/get_signals_count.ts index 9811e5ce21086..b864919fd7295 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/get_signals_count.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/get_signals_count.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AlertServices } from '../../../../../alerting/server'; +import { ElasticsearchClient } from 'kibana/server'; import { buildSignalsSearchQuery } from './build_signals_query'; interface GetSignalsCount { @@ -13,11 +13,7 @@ interface GetSignalsCount { to?: string; ruleId: string; index: string; - callCluster: AlertServices['callCluster']; -} - -interface CountResult { - count: number; + esClient: ElasticsearchClient; } export const getSignalsCount = async ({ @@ -25,7 +21,7 @@ export const getSignalsCount = async ({ to, ruleId, index, - callCluster, + esClient, }: GetSignalsCount): Promise => { if (from == null || to == null) { throw Error('"from" or "to" was not provided to signals count query'); @@ -38,7 +34,7 @@ export const getSignalsCount = async ({ from, }); - const result: CountResult = await callCluster('count', query); + const { body: result } = await esClient.count(query); return result.count; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.test.ts index 4923aa3d1223e..762d7e724f80a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.test.ts @@ -17,6 +17,8 @@ import { sampleEmptyDocSearchResults, } from '../signals/__mocks__/es_results'; import { DEFAULT_RULE_NOTIFICATION_QUERY_SIZE } from '../../../../common/constants'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; jest.mock('./build_signals_query'); describe('rules_notification_alert_type', () => { @@ -70,7 +72,11 @@ describe('rules_notification_alert_type', () => { references: [], attributes: ruleAlert, }); - alertServices.callCluster.mockResolvedValue(sampleDocSearchResultsWithSortId()); + alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise( + sampleDocSearchResultsWithSortId() + ) + ); await alert.executor(payload); @@ -94,7 +100,11 @@ describe('rules_notification_alert_type', () => { references: [], attributes: ruleAlert, }); - alertServices.callCluster.mockResolvedValue(sampleDocSearchResultsWithSortId()); + alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise( + sampleDocSearchResultsWithSortId() + ) + ); await alert.executor(payload); expect(alertServices.alertInstanceFactory).toHaveBeenCalled(); @@ -118,7 +128,11 @@ describe('rules_notification_alert_type', () => { references: [], attributes: ruleAlert, }); - alertServices.callCluster.mockResolvedValue(sampleDocSearchResultsWithSortId()); + alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise( + sampleDocSearchResultsWithSortId() + ) + ); await alert.executor(payload); expect(alertServices.alertInstanceFactory).toHaveBeenCalled(); @@ -143,7 +157,11 @@ describe('rules_notification_alert_type', () => { references: [], attributes: ruleAlert, }); - alertServices.callCluster.mockResolvedValue(sampleDocSearchResultsWithSortId()); + alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise( + sampleDocSearchResultsWithSortId() + ) + ); await alert.executor(payload); expect(alertServices.alertInstanceFactory).toHaveBeenCalled(); @@ -165,7 +183,9 @@ describe('rules_notification_alert_type', () => { references: [], attributes: ruleAlert, }); - alertServices.callCluster.mockResolvedValue(sampleEmptyDocSearchResults()); + alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(sampleEmptyDocSearchResults()) + ); await alert.executor(payload); @@ -180,7 +200,11 @@ describe('rules_notification_alert_type', () => { references: [], attributes: ruleAlert, }); - alertServices.callCluster.mockResolvedValue(sampleDocSearchResultsNoSortIdNoVersion()); + alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise( + sampleDocSearchResultsNoSortIdNoVersion() + ) + ); await alert.executor(payload); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.ts index 6e03eb45da480..a40cb998eb408 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.ts @@ -64,7 +64,7 @@ export const rulesNotificationAlertType = ({ size: DEFAULT_RULE_NOTIFICATION_QUERY_SIZE, index: ruleParams.outputIndex, ruleId: ruleParams.ruleId, - callCluster: services.callCluster, + esClient: services.scopedClusterClient.asCurrentUser, }); const signals = results.hits.hits.map((hit) => hit._source); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/create_index_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/create_index_route.ts index 93b5667b9f629..cd1b77862af04 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/create_index_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/create_index_route.ts @@ -66,9 +66,7 @@ export const createDetectionIndex = async ( context: SecuritySolutionRequestHandlerContext, siemClient: AppClient ): Promise => { - const clusterClient = context.core.elasticsearch.legacy.client; const esClient = context.core.elasticsearch.client.asCurrentUser; - const callCluster = clusterClient.callAsCurrentUser; if (!siemClient) { throw new CreateIndexError('', 404); @@ -76,20 +74,20 @@ export const createDetectionIndex = async ( const index = siemClient.getSignalsIndex(); await ensureMigrationCleanupPolicy({ alias: index, esClient }); - const policyExists = await getPolicyExists(callCluster, index); + const policyExists = await getPolicyExists(esClient, index); if (!policyExists) { - await setPolicy(callCluster, index, signalsPolicy); + await setPolicy(esClient, index, signalsPolicy); } if (await templateNeedsUpdate({ alias: index, esClient })) { - await setTemplate(callCluster, index, getSignalsTemplate(index)); + await setTemplate(esClient, index, getSignalsTemplate(index)); } - const indexExists = await getIndexExists(callCluster, index); + const indexExists = await getIndexExists(esClient, index); if (indexExists) { - const indexVersion = await getIndexVersion(callCluster, index); + const indexVersion = await getIndexVersion(esClient, index); if (isOutdated({ current: indexVersion, target: SIGNALS_TEMPLATE_VERSION })) { - await callCluster('indices.rollover', { alias: index }); + await esClient.indices.rollover({ alias: index }); } } else { - await createBootstrapIndex(callCluster, index); + await createBootstrapIndex(esClient, index); } }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/delete_index_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/delete_index_route.ts index d652bd39c49ce..1a4f00a570424 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/delete_index_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/delete_index_route.ts @@ -38,16 +38,16 @@ export const deleteIndexRoute = (router: SecuritySolutionPluginRouter) => { const siemResponse = buildSiemResponse(response); try { - const clusterClient = context.core.elasticsearch.legacy.client; + const esClient = context.core.elasticsearch.client.asCurrentUser; + const siemClient = context.securitySolution?.getAppClient(); if (!siemClient) { return siemResponse.error({ statusCode: 404 }); } - const callCluster = clusterClient.callAsCurrentUser; const index = siemClient.getSignalsIndex(); - const indexExists = await getIndexExists(callCluster, index); + const indexExists = await getIndexExists(esClient, index); if (!indexExists) { return siemResponse.error({ @@ -55,14 +55,14 @@ export const deleteIndexRoute = (router: SecuritySolutionPluginRouter) => { body: `index: "${index}" does not exist`, }); } else { - await deleteAllIndex(callCluster, `${index}-*`); - const policyExists = await getPolicyExists(callCluster, index); + await deleteAllIndex(esClient, `${index}-*`); + const policyExists = await getPolicyExists(esClient, index); if (policyExists) { - await deletePolicy(callCluster, index); + await deletePolicy(esClient, index); } - const templateExists = await getTemplateExists(callCluster, index); + const templateExists = await getTemplateExists(esClient, index); if (templateExists) { - await deleteTemplate(callCluster, index); + await deleteTemplate(esClient, index); } return response.ok({ body: { acknowledged: true } }); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_index_version.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_index_version.ts index 1ef03b1d9e023..5c626cbe33ac1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_index_version.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_index_version.ts @@ -5,8 +5,9 @@ * 2.0. */ +import { ApiResponse } from '@elastic/elasticsearch'; import { get } from 'lodash'; -import { LegacyAPICaller } from '../../../../../../../../src/core/server'; +import { ElasticsearchClient } from '../../../../../../../../src/core/server'; import { readIndex } from '../../index/read_index'; interface IndicesAliasResponse { @@ -20,10 +21,10 @@ interface IndexAliasResponse { } export const getIndexVersion = async ( - callCluster: LegacyAPICaller, + esClient: ElasticsearchClient, index: string ): Promise => { - const indexAlias: IndicesAliasResponse = await callCluster('indices.getAlias', { + const { body: indexAlias }: ApiResponse = await esClient.indices.getAlias({ index, }); const writeIndex = Object.keys(indexAlias).find( @@ -32,6 +33,6 @@ export const getIndexVersion = async ( if (writeIndex === undefined) { return 0; } - const writeIndexMapping = await readIndex(callCluster, writeIndex); - return get(writeIndexMapping, [writeIndex, 'mappings', '_meta', 'version']) ?? 0; + const writeIndexMapping = await readIndex(esClient, writeIndex); + return get(writeIndexMapping, ['body', writeIndex, 'mappings', '_meta', 'version']) ?? 0; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/read_index_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/read_index_route.ts index 6a2d6c64c211f..01d07f68aa489 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/read_index_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/read_index_route.ts @@ -26,7 +26,7 @@ export const readIndexRoute = (router: SecuritySolutionPluginRouter) => { const siemResponse = buildSiemResponse(response); try { - const clusterClient = context.core.elasticsearch.legacy.client; + const esClient = context.core.elasticsearch.client.asCurrentUser; const siemClient = context.securitySolution?.getAppClient(); if (!siemClient) { @@ -34,12 +34,12 @@ export const readIndexRoute = (router: SecuritySolutionPluginRouter) => { } const index = siemClient.getSignalsIndex(); - const indexExists = await getIndexExists(clusterClient.callAsCurrentUser, index); + const indexExists = await getIndexExists(esClient, index); if (indexExists) { let mappingOutdated: boolean | null = null; try { - const indexVersion = await getIndexVersion(clusterClient.callAsCurrentUser, index); + const indexVersion = await getIndexVersion(esClient, index); mappingOutdated = isOutdated({ current: indexVersion, target: SIGNALS_TEMPLATE_VERSION, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts index 50182a795ca93..cf4b0bcf6f2d9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.test.ts @@ -9,7 +9,6 @@ import { getEmptyFindResult, addPrepackagedRulesRequest, getFindResultWithSingleHit, - getEmptyIndex, getNonEmptyIndex, } from '../__mocks__/request_responses'; import { requestContextMock, serverMock, createMockConfig, mockGetCurrentUser } from '../__mocks__'; @@ -21,6 +20,8 @@ import { listMock } from '../../../../../../lists/server/mocks'; import { siemMock } from '../../../../mocks'; import { FrameworkRequest } from '../../../framework'; import { ExceptionListClient } from '../../../../../../lists/server'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; jest.mock('../../rules/get_prepackaged_rules', () => { return { @@ -101,6 +102,10 @@ describe('add_prepackaged_rules_route', () => { errors: [], }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 1 } }) + ); addPrepackedRulesRoute(server.router, createMockConfig(), securitySetup); }); @@ -125,8 +130,11 @@ describe('add_prepackaged_rules_route', () => { }); test('it returns a 400 if the index does not exist', async () => { - clients.clusterClient.callAsCurrentUser.mockResolvedValue(getEmptyIndex()); const request = addPrepackagedRulesRequest(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 0 } }) + ); const response = await server.inject(request, context); expect(response.status).toEqual(400); @@ -179,9 +187,10 @@ describe('add_prepackaged_rules_route', () => { }); test('catches errors if payloads cause errors to be thrown', async () => { - clients.clusterClient.callAsCurrentUser.mockImplementation(() => { - throw new Error('Test error'); - }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValue( + elasticsearchClientMock.createErrorTransportRequestPromise(new Error('Test error')) + ); const request = addPrepackagedRulesRequest(); const response = await server.inject(request, context); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts index bccf7f4dfffa0..e7e571647cbe4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts @@ -106,7 +106,7 @@ export const createPrepackagedRules = async ( maxTimelineImportExportSize: number, exceptionsClient?: ExceptionListClient ): Promise => { - const clusterClient = context.core.elasticsearch.legacy.client; + const esClient = context.core.elasticsearch.client; const savedObjectsClient = context.core.savedObjects.client; const exceptionsListClient = context.lists != null ? context.lists.getExceptionListClient() : exceptionsClient; @@ -126,7 +126,7 @@ export const createPrepackagedRules = async ( const rulesToUpdate = getRulesToUpdate(rulesFromFileSystem, prepackagedRules); const signalsIndex = siemClient.getSignalsIndex(); if (rulesToInstall.length !== 0 || rulesToUpdate.length !== 0) { - const signalsIndexExists = await getIndexExists(clusterClient.callAsCurrentUser, signalsIndex); + const signalsIndexExists = await getIndexExists(esClient.asCurrentUser, signalsIndex); if (!signalsIndexExists) { throw new PrepackagedRulesError( `Pre-packaged rules cannot be installed until the signals index is created: ${signalsIndex}`, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts index bb9f3ca9c9319..c5cbbeb09ed6d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.test.ts @@ -10,7 +10,6 @@ import { mlServicesMock, mlAuthzMock as mockMlAuthzFactory } from '../../../mach import { buildMlAuthz } from '../../../machine_learning/authz'; import { getReadBulkRequest, - getEmptyIndex, getNonEmptyIndex, getFindResultWithSingleHit, getEmptyFindResult, @@ -20,6 +19,8 @@ import { import { requestContextMock, serverMock, requestMock } from '../__mocks__'; import { createRulesBulkRoute } from './create_rules_bulk_route'; import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/rule_schemas.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create()); @@ -37,6 +38,10 @@ describe('create_rules_bulk', () => { clients.alertsClient.find.mockResolvedValue(getEmptyFindResult()); // no existing rules clients.alertsClient.create.mockResolvedValue(getResult()); // successful creation + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 1 } }) + ); createRulesBulkRoute(server.router, ml); }); @@ -84,7 +89,10 @@ describe('create_rules_bulk', () => { }); it('returns an error object if the index does not exist', async () => { - clients.clusterClient.callAsCurrentUser.mockResolvedValue(getEmptyIndex()); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 0 } }) + ); const response = await server.inject(getReadBulkRequest(), context); expect(response.status).toEqual(200); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts index 6b85c7a40743a..e54c9a4cbb03e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts @@ -43,7 +43,7 @@ export const createRulesBulkRoute = ( async (context, request, response) => { const siemResponse = buildSiemResponse(response); const alertsClient = context.alerting?.getAlertsClient(); - const clusterClient = context.core.elasticsearch.legacy.client; + const esClient = context.core.elasticsearch.client; const savedObjectsClient = context.core.savedObjects.client; const siemClient = context.securitySolution?.getAppClient(); @@ -92,7 +92,7 @@ export const createRulesBulkRoute = ( throwHttpError(await mlAuthz.validateRuleType(internalRule.params.type)); const finalIndex = internalRule.params.outputIndex; - const indexExists = await getIndexExists(clusterClient.callAsCurrentUser, finalIndex); + const indexExists = await getIndexExists(esClient.asCurrentUser, finalIndex); if (!indexExists) { return createBulkErrorObject({ ruleId: internalRule.params.ruleId, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts index 7b998aa2d4252..dd636d5a180d9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.test.ts @@ -12,7 +12,6 @@ import { getCreateRequest, getFindResultStatus, getNonEmptyIndex, - getEmptyIndex, getFindResultWithSingleHit, createMlRuleRequest, } from '../__mocks__/request_responses'; @@ -22,6 +21,8 @@ import { requestContextMock, serverMock, requestMock } from '../__mocks__'; import { createRulesRoute } from './create_rules_route'; import { updateRulesNotifications } from '../../rules/update_rules_notifications'; import { getCreateRulesSchemaMock } from '../../../../../common/detection_engine/schemas/request/rule_schemas.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; jest.mock('../../rules/update_rules_notifications'); jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create()); @@ -40,6 +41,10 @@ describe('create_rules', () => { clients.alertsClient.create.mockResolvedValue(getResult()); // creation succeeds clients.savedObjectsClient.find.mockResolvedValue(getFindResultStatus()); // needed to transform + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 1 } }) + ); createRulesRoute(server.router, ml); }); @@ -102,7 +107,10 @@ describe('create_rules', () => { describe('unhappy paths', () => { test('it returns a 400 if the index does not exist', async () => { - clients.clusterClient.callAsCurrentUser.mockResolvedValue(getEmptyIndex()); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 0 } }) + ); const response = await server.inject(getCreateRequest(), context); expect(response.status).toEqual(400); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts index 309d1bdbb1471..95539319b5a12 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_route.ts @@ -45,7 +45,7 @@ export const createRulesRoute = ( } try { const alertsClient = context.alerting?.getAlertsClient(); - const clusterClient = context.core.elasticsearch.legacy.client; + const esClient = context.core.elasticsearch.client; const savedObjectsClient = context.core.savedObjects.client; const siemClient = context.securitySolution?.getAppClient(); @@ -78,7 +78,7 @@ export const createRulesRoute = ( throwHttpError(await mlAuthz.validateRuleType(internalRule.params.type)); const indexExists = await getIndexExists( - clusterClient.callAsCurrentUser, + esClient.asCurrentUser, internalRule.params.outputIndex ); if (!indexExists) { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.test.ts index 4f29f2d0586ee..0a265adf620ee 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.test.ts @@ -11,7 +11,6 @@ import { getImportRulesRequestOverwriteTrue, getEmptyFindResult, getResult, - getEmptyIndex, getFindResultWithSingleHit, getNonEmptyIndex, } from '../__mocks__/request_responses'; @@ -25,6 +24,8 @@ import { ruleIdsToNdJsonString, rulesToNdJsonString, } from '../../../../../common/detection_engine/schemas/request/import_rules_schema.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; jest.mock('../../../machine_learning/authz', () => mockMlAuthzFactory.create()); @@ -46,6 +47,10 @@ describe('import_rules_route', () => { clients.clusterClient.callAsCurrentUser.mockResolvedValue(getNonEmptyIndex()); // index exists clients.alertsClient.find.mockResolvedValue(getEmptyFindResult()); // no extant rules + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 1 } }) + ); importRulesRoute(server.router, config, ml); }); @@ -124,7 +129,10 @@ describe('import_rules_route', () => { test('returns an error if the index does not exist', async () => { clients.appClient.getSignalsIndex.mockReturnValue('mockSignalsIndex'); - clients.clusterClient.callAsCurrentUser.mockResolvedValue(getEmptyIndex()); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ _shards: { total: 0 } }) + ); const response = await server.inject(request, context); expect(response.status).toEqual(400); expect(response.body).toEqual({ @@ -135,9 +143,12 @@ describe('import_rules_route', () => { }); test('returns an error when cluster throws error', async () => { - clients.clusterClient.callAsCurrentUser.mockImplementation(async () => { - throw new Error('Test error'); - }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (context.core.elasticsearch.client.asCurrentUser.search as any).mockResolvedValue( + elasticsearchClientMock.createErrorTransportRequestPromise({ + body: new Error('Test error'), + }) + ); const response = await server.inject(request, context); expect(response.status).toEqual(500); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts index 27231ab896b7e..b37cc41f1439e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts @@ -77,7 +77,7 @@ export const importRulesRoute = ( try { const alertsClient = context.alerting?.getAlertsClient(); - const clusterClient = context.core.elasticsearch.legacy.client; + const esClient = context.core.elasticsearch.client; const savedObjectsClient = context.core.savedObjects.client; const siemClient = context.securitySolution?.getAppClient(); @@ -101,7 +101,7 @@ export const importRulesRoute = ( }); } const signalsIndex = siemClient.getSignalsIndex(); - const indexExists = await getIndexExists(clusterClient.callAsCurrentUser, signalsIndex); + const indexExists = await getIndexExists(esClient.asCurrentUser, signalsIndex); if (!indexExists) { return siemResponse.error({ statusCode: 400, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_events_query.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_events_query.test.ts index 8597667f64657..4b74f865c6a53 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_events_query.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_events_query.test.ts @@ -20,10 +20,10 @@ describe('create_signals', () => { excludeDocsWithTimestampOverride: false, }); expect(query).toEqual({ - allowNoIndices: true, + allow_no_indices: true, index: ['auditbeat-*'], size: 100, - ignoreUnavailable: true, + ignore_unavailable: true, body: { docvalue_fields: [ { @@ -66,6 +66,7 @@ describe('create_signals', () => { { '@timestamp': { order: 'asc', + unmapped_type: 'date', }, }, ], @@ -84,10 +85,10 @@ describe('create_signals', () => { excludeDocsWithTimestampOverride: false, }); expect(query).toEqual({ - allowNoIndices: true, + allow_no_indices: true, index: ['auditbeat-*'], size: 100, - ignoreUnavailable: true, + ignore_unavailable: true, body: { docvalue_fields: [ { @@ -130,6 +131,7 @@ describe('create_signals', () => { { '@timestamp': { order: 'asc', + unmapped_type: 'date', }, }, ], @@ -149,10 +151,10 @@ describe('create_signals', () => { excludeDocsWithTimestampOverride: false, }); expect(query).toEqual({ - allowNoIndices: true, + allow_no_indices: true, index: ['auditbeat-*'], size: 100, - ignoreUnavailable: true, + ignore_unavailable: true, body: { docvalue_fields: [ { @@ -191,14 +193,15 @@ describe('create_signals', () => { include_unmapped: true, }, ], + search_after: [fakeSortId], sort: [ { '@timestamp': { order: 'asc', + unmapped_type: 'date', }, }, ], - search_after: [fakeSortId], }, }); }); @@ -215,10 +218,10 @@ describe('create_signals', () => { excludeDocsWithTimestampOverride: false, }); expect(query).toEqual({ - allowNoIndices: true, + allow_no_indices: true, index: ['auditbeat-*'], size: 100, - ignoreUnavailable: true, + ignore_unavailable: true, body: { docvalue_fields: [ { @@ -257,14 +260,15 @@ describe('create_signals', () => { include_unmapped: true, }, ], + search_after: [fakeSortIdNumber], sort: [ { '@timestamp': { order: 'asc', + unmapped_type: 'date', }, }, ], - search_after: [fakeSortIdNumber], }, }); }); @@ -280,10 +284,10 @@ describe('create_signals', () => { excludeDocsWithTimestampOverride: false, }); expect(query).toEqual({ - allowNoIndices: true, + allow_no_indices: true, index: ['auditbeat-*'], size: 100, - ignoreUnavailable: true, + ignore_unavailable: true, body: { docvalue_fields: [ { @@ -326,6 +330,7 @@ describe('create_signals', () => { { '@timestamp': { order: 'asc', + unmapped_type: 'date', }, }, ], @@ -352,10 +357,10 @@ describe('create_signals', () => { excludeDocsWithTimestampOverride: false, }); expect(query).toEqual({ - allowNoIndices: true, + allow_no_indices: true, index: ['auditbeat-*'], size: 100, - ignoreUnavailable: true, + ignore_unavailable: true, body: { docvalue_fields: [{ field: '@timestamp', format: 'strict_date_optional_time' }], query: { @@ -400,6 +405,7 @@ describe('create_signals', () => { { '@timestamp': { order: 'asc', + unmapped_type: 'date', }, }, ], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_events_query.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_events_query.ts index f8fd4ed30d6ee..bce9adc9f0f88 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_events_query.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/build_events_query.ts @@ -73,10 +73,10 @@ export const buildEventsSearchQuery = ({ const filterWithTime = [filter, { bool: { filter: rangeFilter } }]; const searchQuery = { - allowNoIndices: true, + allow_no_indices: true, index, size, - ignoreUnavailable: true, + ignore_unavailable: true, body: { docvalue_fields: docFields, query: { @@ -100,6 +100,7 @@ export const buildEventsSearchQuery = ({ { [sortField]: { order: sortOrder ?? 'asc', + unmapped_type: 'date', }, }, ], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/search_after_bulk_create.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/search_after_bulk_create.test.ts index ead9da533d775..ccefa24e2018c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/search_after_bulk_create.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/search_after_bulk_create.test.ts @@ -26,6 +26,8 @@ import { BulkResponse, RuleRangeTuple } from './types'; import { SearchListItemArraySchema } from '../../../../../lists/common/schemas'; import { getSearchListItemResponseMock } from '../../../../../lists/common/schemas/response/search_list_item_schema.mock'; import { getRuleRangeTuples } from './utils'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; const buildRuleMessage = buildRuleMessageFactory({ id: 'fake id', @@ -59,9 +61,14 @@ describe('searchAfterAndBulkCreate', () => { }); test('should return success with number of searches less than max signals', async () => { - mockService.callCluster - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(0, 3))) - .mockResolvedValueOnce({ + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(0, 3)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -72,8 +79,16 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(3, 6))) - .mockResolvedValueOnce({ + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(3, 6)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -84,8 +99,16 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(6, 9))) - .mockResolvedValueOnce({ + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(6, 9)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -96,8 +119,16 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(9, 12))) - .mockResolvedValueOnce({ + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(9, 12)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -108,7 +139,13 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(sampleDocSearchResultsNoSortIdNoHits()); + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + sampleDocSearchResultsNoSortIdNoHits() + ) + ); const exceptionItem = getExceptionListItemSchemaMock(); exceptionItem.entries = [ @@ -149,15 +186,19 @@ describe('searchAfterAndBulkCreate', () => { buildRuleMessage, }); expect(success).toEqual(true); - expect(mockService.callCluster).toHaveBeenCalledTimes(9); + expect(mockService.scopedClusterClient.asCurrentUser.search).toHaveBeenCalledTimes(5); expect(createdSignalsCount).toEqual(4); expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); }); test('should return success with number of searches less than max signals with gap', async () => { - mockService.callCluster - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(0, 3))) - .mockResolvedValueOnce({ + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(0, 3)) + ) + ); + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -168,8 +209,16 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(3, 6))) - .mockResolvedValueOnce({ + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(3, 6)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -180,8 +229,16 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(6, 9))) - .mockResolvedValueOnce({ + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(6, 9)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -192,7 +249,13 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(sampleDocSearchResultsNoSortIdNoHits()); + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + sampleDocSearchResultsNoSortIdNoHits() + ) + ); const exceptionItem = getExceptionListItemSchemaMock(); exceptionItem.entries = [ @@ -233,15 +296,20 @@ describe('searchAfterAndBulkCreate', () => { buildRuleMessage, }); expect(success).toEqual(true); - expect(mockService.callCluster).toHaveBeenCalledTimes(7); + expect(mockService.scopedClusterClient.asCurrentUser.search).toHaveBeenCalledTimes(4); expect(createdSignalsCount).toEqual(3); expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); }); test('should return success when no search results are in the allowlist', async () => { - mockService.callCluster - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3))) - .mockResolvedValueOnce({ + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -267,7 +335,13 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(sampleDocSearchResultsNoSortIdNoHits()); + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + sampleDocSearchResultsNoSortIdNoHits() + ) + ); const exceptionItem = getExceptionListItemSchemaMock(); exceptionItem.entries = [ @@ -308,7 +382,7 @@ describe('searchAfterAndBulkCreate', () => { buildRuleMessage, }); expect(success).toEqual(true); - expect(mockService.callCluster).toHaveBeenCalledTimes(3); + expect(mockService.scopedClusterClient.asCurrentUser.search).toHaveBeenCalledTimes(2); expect(createdSignalsCount).toEqual(4); expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); }); @@ -320,16 +394,22 @@ describe('searchAfterAndBulkCreate', () => { { ...getSearchListItemResponseMock(), value: ['3.3.3.3'] }, ]; listClient.searchListItemByValues = jest.fn().mockResolvedValue(searchListItems); - mockService.callCluster + mockService.scopedClusterClient.asCurrentUser.search .mockResolvedValueOnce( - repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3), [ - '1.1.1.1', - '2.2.2.2', - '2.2.2.2', - '2.2.2.2', - ]) + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3), [ + '1.1.1.1', + '2.2.2.2', + '2.2.2.2', + '2.2.2.2', + ]) + ) ) - .mockResolvedValueOnce(sampleDocSearchResultsNoSortIdNoHits()); + .mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + sampleDocSearchResultsNoSortIdNoHits() + ) + ); const exceptionItem = getExceptionListItemSchemaMock(); exceptionItem.entries = [ @@ -370,7 +450,7 @@ describe('searchAfterAndBulkCreate', () => { buildRuleMessage, }); expect(success).toEqual(true); - expect(mockService.callCluster).toHaveBeenCalledTimes(2); + expect(mockService.scopedClusterClient.asCurrentUser.search).toHaveBeenCalledTimes(2); expect(createdSignalsCount).toEqual(0); // should not create any signals because all events were in the allowlist expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); }); @@ -384,13 +464,15 @@ describe('searchAfterAndBulkCreate', () => { ]; listClient.searchListItemByValues = jest.fn().mockResolvedValue(searchListItems); - mockService.callCluster.mockResolvedValueOnce( - repeatedSearchResultsWithNoSortId(4, 4, someGuids.slice(0, 3), [ - '1.1.1.1', - '2.2.2.2', - '2.2.2.2', - '2.2.2.2', - ]) + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithNoSortId(4, 4, someGuids.slice(0, 3), [ + '1.1.1.1', + '2.2.2.2', + '2.2.2.2', + '2.2.2.2', + ]) + ) ); const exceptionItem = getExceptionListItemSchemaMock(); @@ -432,7 +514,7 @@ describe('searchAfterAndBulkCreate', () => { buildRuleMessage, }); expect(success).toEqual(true); - expect(mockService.callCluster).toHaveBeenCalledTimes(1); + expect(mockService.scopedClusterClient.asCurrentUser.search).toHaveBeenCalledTimes(1); expect(createdSignalsCount).toEqual(0); // should not create any signals because all events were in the allowlist expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); // I don't like testing log statements since logs change but this is the best @@ -443,9 +525,14 @@ describe('searchAfterAndBulkCreate', () => { }); test('should return success when no sortId present but search results are in the allowlist', async () => { - mockService.callCluster - .mockResolvedValueOnce(repeatedSearchResultsWithNoSortId(4, 4, someGuids.slice(0, 3))) - .mockResolvedValueOnce({ + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithNoSortId(4, 4, someGuids.slice(0, 3)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -470,7 +557,8 @@ describe('searchAfterAndBulkCreate', () => { }, }, ], - }); + }) + ); const exceptionItem = getExceptionListItemSchemaMock(); exceptionItem.entries = [ @@ -511,7 +599,7 @@ describe('searchAfterAndBulkCreate', () => { buildRuleMessage, }); expect(success).toEqual(true); - expect(mockService.callCluster).toHaveBeenCalledTimes(2); + expect(mockService.scopedClusterClient.asCurrentUser.search).toHaveBeenCalledTimes(1); expect(createdSignalsCount).toEqual(4); expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); // I don't like testing log statements since logs change but this is the best @@ -522,9 +610,14 @@ describe('searchAfterAndBulkCreate', () => { }); test('should return success when no exceptions list provided', async () => { - mockService.callCluster - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3))) - .mockResolvedValueOnce({ + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 4, someGuids.slice(0, 3)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -550,7 +643,13 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(sampleDocSearchResultsNoSortIdNoHits()); + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + sampleDocSearchResultsNoSortIdNoHits() + ) + ); listClient.searchListItemByValues = jest.fn(({ value }) => Promise.resolve( @@ -587,7 +686,7 @@ describe('searchAfterAndBulkCreate', () => { buildRuleMessage, }); expect(success).toEqual(true); - expect(mockService.callCluster).toHaveBeenCalledTimes(3); + expect(mockService.scopedClusterClient.asCurrentUser.search).toHaveBeenCalledTimes(2); expect(createdSignalsCount).toEqual(4); expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); }); @@ -605,9 +704,14 @@ describe('searchAfterAndBulkCreate', () => { }, }, ]; - mockService.callCluster - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(0, 3))) - .mockRejectedValue(new Error('bulk failed')); // Added this recently + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(0, 3)) + ) + ); + mockService.scopedClusterClient.asCurrentUser.bulk.mockRejectedValue( + elasticsearchClientMock.createErrorTransportRequestPromise(new Error('bulk failed')) + ); // Added this recently const { success, createdSignalsCount, lastLookBackDate } = await searchAfterAndBulkCreate({ listClient, exceptionsList: [exceptionItem], @@ -653,7 +757,9 @@ describe('searchAfterAndBulkCreate', () => { }, }, ]; - mockService.callCluster.mockResolvedValueOnce(sampleEmptyDocSearchResults()); + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise(sampleEmptyDocSearchResults()) + ); listClient.searchListItemByValues = jest.fn(({ value }) => Promise.resolve( value.slice(0, 2).map((item) => ({ @@ -694,18 +800,20 @@ describe('searchAfterAndBulkCreate', () => { }); test('if returns false when singleSearchAfter throws an exception', async () => { - mockService.callCluster - .mockResolvedValueOnce({ - took: 100, - errors: false, - items: [ - { - create: { - status: 201, + mockService.scopedClusterClient.asCurrentUser.search + .mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + took: 100, + errors: false, + items: [ + { + create: { + status: 201, + }, }, - }, - ], - }) + ], + }) + ) .mockImplementation(() => { throw Error('Fake Error'); // throws the exception we are testing }); @@ -781,11 +889,24 @@ describe('searchAfterAndBulkCreate', () => { }, ], }; - mockService.callCluster - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(0, 3))) - .mockResolvedValueOnce(bulkItem) // adds the response with errors we are testing - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(3, 6))) - .mockResolvedValueOnce({ + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(0, 3)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise(bulkItem) + ); // adds the response with errors we are testing + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(3, 6)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -796,8 +917,16 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(6, 9))) - .mockResolvedValueOnce({ + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(6, 9)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -808,8 +937,16 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(9, 12))) - .mockResolvedValueOnce({ + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(9, 12)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -820,7 +957,13 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(sampleDocSearchResultsNoSortIdNoHits()); + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + sampleDocSearchResultsNoSortIdNoHits() + ) + ); const { success, createdSignalsCount, @@ -854,15 +997,20 @@ describe('searchAfterAndBulkCreate', () => { }); expect(success).toEqual(false); expect(errors).toEqual(['error on creation']); - expect(mockService.callCluster).toHaveBeenCalledTimes(9); + expect(mockService.scopedClusterClient.asCurrentUser.search).toHaveBeenCalledTimes(5); expect(createdSignalsCount).toEqual(4); expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); }); it('invokes the enrichment callback with signal search results', async () => { - mockService.callCluster - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(0, 3))) - .mockResolvedValueOnce({ + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(0, 3)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -873,8 +1021,16 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(3, 6))) - .mockResolvedValueOnce({ + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(3, 6)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -885,8 +1041,16 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(repeatedSearchResultsWithSortId(4, 1, someGuids.slice(6, 9))) - .mockResolvedValueOnce({ + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + repeatedSearchResultsWithSortId(4, 1, someGuids.slice(6, 9)) + ) + ); + + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ took: 100, errors: false, items: [ @@ -897,7 +1061,13 @@ describe('searchAfterAndBulkCreate', () => { }, ], }) - .mockResolvedValueOnce(sampleDocSearchResultsNoSortIdNoHits()); + ); + + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + sampleDocSearchResultsNoSortIdNoHits() + ) + ); const mockEnrichment = jest.fn((a) => a); const { success, createdSignalsCount, lastLookBackDate } = await searchAfterAndBulkCreate({ @@ -941,7 +1111,7 @@ describe('searchAfterAndBulkCreate', () => { }) ); expect(success).toEqual(true); - expect(mockService.callCluster).toHaveBeenCalledTimes(7); + expect(mockService.scopedClusterClient.asCurrentUser.search).toHaveBeenCalledTimes(4); expect(createdSignalsCount).toEqual(3); expect(lastLookBackDate).toEqual(new Date('2020-04-20T21:27:45+0000')); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts index 4079cbb852de4..bcd04ed5e15cd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts @@ -30,6 +30,8 @@ import { getExceptionListClientMock } from '../../../../../lists/server/services import { getExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; import { ApiResponse } from '@elastic/elasticsearch/lib/Transport'; import { getEntryListMock } from '../../../../../lists/common/schemas/types/entry_list.mock'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; jest.mock('./rule_status_saved_objects_client'); jest.mock('./rule_status_service'); @@ -140,11 +142,13 @@ describe('rules_notification_alert_type', () => { ), }; }); - alertServices.callCluster.mockResolvedValue({ - hits: { - total: { value: 10 }, - }, - }); + alertServices.scopedClusterClient.asCurrentUser.transport.request.mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + hits: { + total: { value: 10 }, + }, + }) + ); const value: Partial = { statusCode: 200, body: { @@ -160,7 +164,9 @@ describe('rules_notification_alert_type', () => { }, }, }; - alertServices.scopedClusterClient.fieldCaps.mockResolvedValue(value as ApiResponse); + alertServices.scopedClusterClient.asCurrentUser.fieldCaps.mockResolvedValue( + value as ApiResponse + ); const ruleAlert = getResult(); alertServices.savedObjectsClient.get.mockResolvedValue({ id: 'id', @@ -665,7 +671,9 @@ describe('rules_notification_alert_type', () => { }); it('and call ruleStatusService with the default message', async () => { - (searchAfterAndBulkCreate as jest.Mock).mockRejectedValue({}); + (searchAfterAndBulkCreate as jest.Mock).mockRejectedValue( + elasticsearchClientMock.createErrorTransportRequestPromise({}) + ); await alert.executor(payload); expect(logger.error).toHaveBeenCalled(); expect(logger.error.mock.calls[0][0]).toContain('An error occurred during rule execution'); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts index 65efd25c9fba2..cd77cab01bb01 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -12,6 +12,7 @@ import isEmpty from 'lodash/isEmpty'; import { chain, tryCatch } from 'fp-ts/lib/TaskEither'; import { flow } from 'fp-ts/lib/function'; +import { ApiResponse } from '@elastic/elasticsearch'; import { performance } from 'perf_hooks'; import { toError, toPromise } from '../../../../common/fp_utils'; @@ -198,7 +199,7 @@ export const signalRulesAlertType = ({ const inputIndices = await getInputIndex(services, version, index); const [privileges, timestampFieldCaps] = await Promise.all([ checkPrivileges(services, inputIndices), - services.scopedClusterClient.fieldCaps({ + services.scopedClusterClient.asCurrentUser.fieldCaps({ index, fields: hasTimestampOverride ? ['@timestamp', timestampOverride as string] @@ -583,7 +584,10 @@ export const signalRulesAlertType = ({ wroteWarningStatus = true; } try { - const signalIndexVersion = await getIndexVersion(services.callCluster, outputIndex); + const signalIndexVersion = await getIndexVersion( + services.scopedClusterClient.asCurrentUser, + outputIndex + ); if (isOutdated({ current: signalIndexVersion, target: MIN_EQL_RULE_INDEX_VERSION })) { throw new Error( `EQL based rules require an update to version ${MIN_EQL_RULE_INDEX_VERSION} of the detection alerts index mapping` @@ -610,10 +614,11 @@ export const signalRulesAlertType = ({ eventCategoryOverride ); const eqlSignalSearchStart = performance.now(); - const response: EqlSignalSearchResponse = await services.callCluster( - 'transport.request', + const { + body: response, + } = (await services.scopedClusterClient.asCurrentUser.transport.request( request - ); + )) as ApiResponse; const eqlSignalSearchEnd = performance.now(); const eqlSearchDuration = makeFloatString(eqlSignalSearchEnd - eqlSignalSearchStart); result.searchAfterTimes = [eqlSearchDuration]; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.test.ts index 8ade6460cbffc..eecedb02b2687 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.test.ts @@ -21,6 +21,8 @@ import { DEFAULT_SIGNALS_INDEX } from '../../../../common/constants'; import { singleBulkCreate, filterDuplicateRules } from './single_bulk_create'; import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mocks'; import { buildRuleMessageFactory } from './rule_messages'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; const buildRuleMessage = buildRuleMessageFactory({ id: 'fake id', @@ -139,15 +141,17 @@ describe('singleBulkCreate', () => { test('create successful bulk create', async () => { const sampleParams = sampleRuleAlertParams(); - mockService.callCluster.mockResolvedValueOnce({ - took: 100, - errors: false, - items: [ - { - fakeItemValue: 'fakeItemKey', - }, - ], - }); + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + took: 100, + errors: false, + items: [ + { + fakeItemValue: 'fakeItemKey', + }, + ], + }) + ); const { success, createdItemsCount } = await singleBulkCreate({ filteredEvents: sampleDocSearchResultsNoSortId(), ruleParams: sampleParams, @@ -174,15 +178,17 @@ describe('singleBulkCreate', () => { test('create successful bulk create with docs with no versioning', async () => { const sampleParams = sampleRuleAlertParams(); - mockService.callCluster.mockResolvedValueOnce({ - took: 100, - errors: false, - items: [ - { - fakeItemValue: 'fakeItemKey', - }, - ], - }); + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + took: 100, + errors: false, + items: [ + { + fakeItemValue: 'fakeItemKey', + }, + ], + }) + ); const { success, createdItemsCount } = await singleBulkCreate({ filteredEvents: sampleDocSearchResultsNoSortIdNoVersion(), ruleParams: sampleParams, @@ -209,7 +215,9 @@ describe('singleBulkCreate', () => { test('create unsuccessful bulk create due to empty search results', async () => { const sampleParams = sampleRuleAlertParams(); - mockService.callCluster.mockResolvedValue(false); + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(false) + ); const { success, createdItemsCount } = await singleBulkCreate({ filteredEvents: sampleEmptyDocSearchResults(), ruleParams: sampleParams, @@ -237,7 +245,9 @@ describe('singleBulkCreate', () => { test('create successful bulk create when bulk create has duplicate errors', async () => { const sampleParams = sampleRuleAlertParams(); const sampleSearchResult = sampleDocSearchResultsNoSortId; - mockService.callCluster.mockResolvedValue(sampleBulkCreateDuplicateResult); + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(sampleBulkCreateDuplicateResult) + ); const { success, createdItemsCount } = await singleBulkCreate({ filteredEvents: sampleSearchResult(), ruleParams: sampleParams, @@ -267,7 +277,9 @@ describe('singleBulkCreate', () => { test('create failed bulk create when bulk create has multiple error statuses', async () => { const sampleParams = sampleRuleAlertParams(); const sampleSearchResult = sampleDocSearchResultsNoSortId; - mockService.callCluster.mockResolvedValue(sampleBulkCreateErrorResult); + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValue( + elasticsearchClientMock.createSuccessTransportRequestPromise(sampleBulkCreateErrorResult) + ); const { success, createdItemsCount, errors } = await singleBulkCreate({ filteredEvents: sampleSearchResult(), ruleParams: sampleParams, @@ -335,7 +347,9 @@ describe('singleBulkCreate', () => { test('create successful and returns proper createdItemsCount', async () => { const sampleParams = sampleRuleAlertParams(); - mockService.callCluster.mockResolvedValue(sampleBulkCreateDuplicateResult); + mockService.scopedClusterClient.asCurrentUser.bulk.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise(sampleBulkCreateDuplicateResult) + ); const { success, createdItemsCount } = await singleBulkCreate({ filteredEvents: sampleDocSearchResultsNoSortId(), ruleParams: sampleParams, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.ts index 4d66a1fe7de92..6c791bc4d0ee3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_bulk_create.ts @@ -158,7 +158,7 @@ export const singleBulkCreate = async ({ }), ]); const start = performance.now(); - const response: BulkResponse = await services.callCluster('bulk', { + const { body: response } = await services.scopedClusterClient.asCurrentUser.bulk({ index: signalsIndex, refresh, body: bulkBody, @@ -244,7 +244,7 @@ export const bulkInsertSignals = async ( doc._source, ]); const start = performance.now(); - const response: BulkResponse = await services.callCluster('bulk', { + const { body: response } = await services.scopedClusterClient.asCurrentUser.bulk({ refresh, body: bulkBody, }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.test.ts index c3fb5a2b0a739..a325903c66ec0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.test.ts @@ -14,6 +14,8 @@ import { singleSearchAfter } from './single_search_after'; import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mocks'; import { ShardError } from '../../types'; import { buildRuleMessageFactory } from './rule_messages'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; const buildRuleMessage = buildRuleMessageFactory({ id: 'fake id', @@ -29,7 +31,9 @@ describe('singleSearchAfter', () => { }); test('if singleSearchAfter works without a given sort id', async () => { - mockService.callCluster.mockResolvedValue(sampleDocSearchResultsNoSortId()); + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise(sampleDocSearchResultsNoSortId()) + ); const { searchResult } = await singleSearchAfter({ searchAfterSortId: undefined, index: [], @@ -46,7 +50,9 @@ describe('singleSearchAfter', () => { expect(searchResult).toEqual(sampleDocSearchResultsNoSortId()); }); test('if singleSearchAfter returns an empty failure array', async () => { - mockService.callCluster.mockResolvedValue(sampleDocSearchResultsNoSortId()); + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise(sampleDocSearchResultsNoSortId()) + ); const { searchErrors } = await singleSearchAfter({ searchAfterSortId: undefined, index: [], @@ -80,22 +86,24 @@ describe('singleSearchAfter', () => { }, }, ]; - mockService.callCluster.mockResolvedValue({ - took: 10, - timed_out: false, - _shards: { - total: 10, - successful: 10, - failed: 1, - skipped: 0, - failures: errors, - }, - hits: { - total: 100, - max_score: 100, - hits: [], - }, - }); + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise({ + took: 10, + timed_out: false, + _shards: { + total: 10, + successful: 10, + failed: 1, + skipped: 0, + failures: errors, + }, + hits: { + total: 100, + max_score: 100, + hits: [], + }, + }) + ); const { searchErrors } = await singleSearchAfter({ searchAfterSortId: undefined, index: [], @@ -115,7 +123,11 @@ describe('singleSearchAfter', () => { }); test('if singleSearchAfter works with a given sort id', async () => { const searchAfterSortId = '1234567891111'; - mockService.callCluster.mockResolvedValue(sampleDocSearchResultsWithSortId()); + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + sampleDocSearchResultsWithSortId() + ) + ); const { searchResult } = await singleSearchAfter({ searchAfterSortId, index: [], @@ -133,9 +145,9 @@ describe('singleSearchAfter', () => { }); test('if singleSearchAfter throws error', async () => { const searchAfterSortId = '1234567891111'; - mockService.callCluster.mockImplementation(async () => { - throw Error('Fake Error'); - }); + mockService.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createErrorTransportRequestPromise(new Error('Fake Error')) + ); await expect( singleSearchAfter({ searchAfterSortId, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts index f7b30cd7f2e83..b35c68c8deacd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts @@ -72,8 +72,9 @@ export const singleSearchAfter = async ({ }); const start = performance.now(); - const nextSearchAfterResult: SignalSearchResponse = await services.callCluster( - 'search', + const { + body: nextSearchAfterResult, + } = await services.scopedClusterClient.asCurrentUser.search( searchAfterQuery ); const end = performance.now(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/build_threat_enrichment.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/build_threat_enrichment.ts index 7d6cd655e336d..3a2a8fcbebf6e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/build_threat_enrichment.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/build_threat_enrichment.ts @@ -34,7 +34,7 @@ export const buildThreatEnrichment = ({ }, }; const threatResponse = await getThreatList({ - callCluster: services.callCluster, + esClient: services.scopedClusterClient.asCurrentUser, exceptionItems, threatFilters: [...threatFilters, matchedThreatsFilter], query: threatQuery, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/create_threat_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/create_threat_signals.ts index 854c2b8f3fdc1..e0be48458b049 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/create_threat_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/create_threat_signals.ts @@ -66,7 +66,7 @@ export const createThreatSignals = async ({ }; let threatListCount = await getThreatListCount({ - callCluster: services.callCluster, + esClient: services.scopedClusterClient.asCurrentUser, exceptionItems, threatFilters, query: threatQuery, @@ -76,7 +76,7 @@ export const createThreatSignals = async ({ logger.debug(buildRuleMessage(`Total indicator items: ${threatListCount}`)); let threatList = await getThreatList({ - callCluster: services.callCluster, + esClient: services.scopedClusterClient.asCurrentUser, exceptionItems, threatFilters, query: threatQuery, @@ -166,7 +166,7 @@ export const createThreatSignals = async ({ logger.debug(buildRuleMessage(`Indicator items left to check are ${threatListCount}`)); threatList = await getThreatList({ - callCluster: services.callCluster, + esClient: services.scopedClusterClient.asCurrentUser, exceptionItems, query: threatQuery, language: threatLanguage, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/get_threat_list.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/get_threat_list.ts index 92d4e5cf8a93b..a2a51d3a060c1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/get_threat_list.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/get_threat_list.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { ApiResponse } from '@elastic/elasticsearch'; import { SearchResponse } from 'elasticsearch'; import { getQueryFilter } from '../../../../../common/detection_engine/get_query_filter'; import { @@ -21,7 +22,7 @@ import { export const MAX_PER_PAGE = 9000; export const getThreatList = async ({ - callCluster, + esClient, query, language, index, @@ -52,7 +53,7 @@ export const getThreatList = async ({ `Querying the indicator items from the index: "${index}" with searchAfter: "${searchAfter}" for up to ${calculatedPerPage} indicator items` ) ); - const response: SearchResponse = await callCluster('search', { + const { body: response } = await esClient.search>({ body: { query: queryFilter, fields: [ @@ -69,7 +70,7 @@ export const getThreatList = async ({ listItemIndex: listClient.getListItemIndex(), }), }, - ignoreUnavailable: true, + ignore_unavailable: true, index, size: calculatedPerPage, }); @@ -108,7 +109,7 @@ export const getSortWithTieBreaker = ({ }; export const getThreatListCount = async ({ - callCluster, + esClient, query, language, threatFilters, @@ -122,13 +123,15 @@ export const getThreatListCount = async ({ index, exceptionItems ); - const response: { + const { + body: response, + }: ApiResponse<{ count: number; - } = await callCluster('count', { + }> = await esClient.count({ body: { query: queryFilter, }, - ignoreUnavailable: true, + ignore_unavailable: true, index, }); return response.count; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts index 7d0ab3a2b6d25..0c14f906742d4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts @@ -29,7 +29,7 @@ import { AlertServices, } from '../../../../../../alerting/server'; import { ExceptionListItemSchema } from '../../../../../../lists/common/schemas'; -import { ILegacyScopedClusterClient, Logger } from '../../../../../../../../src/core/server'; +import { ElasticsearchClient, Logger } from '../../../../../../../../src/core/server'; import { RuleAlertAction } from '../../../../../common/detection_engine/types'; import { TelemetryEventsSender } from '../../../telemetry/sender'; import { BuildRuleMessage } from '../rule_messages'; @@ -148,7 +148,7 @@ export interface BooleanFilter { } export interface GetThreatListOptions { - callCluster: ILegacyScopedClusterClient['callAsCurrentUser']; + esClient: ElasticsearchClient; query: string; language: ThreatLanguageOrUndefined; index: string[]; @@ -164,7 +164,7 @@ export interface GetThreatListOptions { } export interface ThreatListCountOptions { - callCluster: ILegacyScopedClusterClient['callAsCurrentUser']; + esClient: ElasticsearchClient; query: string; language: ThreatLanguageOrUndefined; threatFilters: PartialFilter[]; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts index 48e3da7404f51..fa2fa1f102bd1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts @@ -155,18 +155,20 @@ export const checkPrivileges = async ( services: AlertServices, indices: string[] ): Promise => - services.callCluster('transport.request', { - path: '/_security/user/_has_privileges', - method: 'POST', - body: { - index: [ - { - names: indices ?? [], - privileges: ['read'], - }, - ], - }, - }); + ( + await services.scopedClusterClient.asCurrentUser.transport.request({ + path: '/_security/user/_has_privileges', + method: 'POST', + body: { + index: [ + { + names: indices ?? [], + privileges: ['read'], + }, + ], + }, + }) + ).body as Privilege; export const getNumCatchupIntervals = ({ gap, @@ -205,7 +207,11 @@ export const getListsClient = ({ throw new Error('lists plugin unavailable during rule execution'); } - const listClient = lists.getListClient(services.callCluster, spaceId, updatedByUser ?? 'elastic'); + const listClient = lists.getListClient( + services.scopedClusterClient.asCurrentUser, + spaceId, + updatedByUser ?? 'elastic' + ); const exceptionsClient = lists.getExceptionListClient( savedObjectClient, updatedByUser ?? 'elastic' diff --git a/x-pack/plugins/stack_alerts/common/build_sorted_events_query.test.ts b/x-pack/plugins/stack_alerts/common/build_sorted_events_query.test.ts index cc554b8468d1e..39530ea7b7741 100644 --- a/x-pack/plugins/stack_alerts/common/build_sorted_events_query.test.ts +++ b/x-pack/plugins/stack_alerts/common/build_sorted_events_query.test.ts @@ -26,10 +26,10 @@ describe('buildSortedEventsQuery', () => { test('it builds a filter with given date range', () => { expect(buildSortedEventsQuery(query)).toEqual({ - allowNoIndices: true, + allow_no_indices: true, index: ['index-name'], size: 100, - ignoreUnavailable: true, + ignore_unavailable: true, track_total_hits: false, body: { docvalue_fields: [ @@ -77,10 +77,10 @@ describe('buildSortedEventsQuery', () => { test('it does not include searchAfterSortId if it is an empty string', () => { query.searchAfterSortId = ''; expect(buildSortedEventsQuery(query)).toEqual({ - allowNoIndices: true, + allow_no_indices: true, index: ['index-name'], size: 100, - ignoreUnavailable: true, + ignore_unavailable: true, track_total_hits: false, body: { docvalue_fields: [ @@ -129,10 +129,10 @@ describe('buildSortedEventsQuery', () => { const sortId = '123456789012'; query.searchAfterSortId = sortId; expect(buildSortedEventsQuery(query)).toEqual({ - allowNoIndices: true, + allow_no_indices: true, index: ['index-name'], size: 100, - ignoreUnavailable: true, + ignore_unavailable: true, track_total_hits: false, body: { docvalue_fields: [ @@ -182,10 +182,10 @@ describe('buildSortedEventsQuery', () => { const sortId = 123456789012; query.searchAfterSortId = sortId; expect(buildSortedEventsQuery(query)).toEqual({ - allowNoIndices: true, + allow_no_indices: true, index: ['index-name'], size: 100, - ignoreUnavailable: true, + ignore_unavailable: true, track_total_hits: false, body: { docvalue_fields: [ @@ -240,10 +240,10 @@ describe('buildSortedEventsQuery', () => { }, }; expect(buildSortedEventsQuery(query)).toEqual({ - allowNoIndices: true, + allow_no_indices: true, index: ['index-name'], size: 100, - ignoreUnavailable: true, + ignore_unavailable: true, track_total_hits: false, body: { docvalue_fields: [ @@ -298,10 +298,10 @@ describe('buildSortedEventsQuery', () => { test('it uses sortOrder if specified', () => { query.sortOrder = 'desc'; expect(buildSortedEventsQuery(query)).toEqual({ - allowNoIndices: true, + allow_no_indices: true, index: ['index-name'], size: 100, - ignoreUnavailable: true, + ignore_unavailable: true, track_total_hits: false, body: { docvalue_fields: [ @@ -349,10 +349,10 @@ describe('buildSortedEventsQuery', () => { test('it uses track_total_hits if specified', () => { query.track_total_hits = true; expect(buildSortedEventsQuery(query)).toEqual({ - allowNoIndices: true, + allow_no_indices: true, index: ['index-name'], size: 100, - ignoreUnavailable: true, + ignore_unavailable: true, track_total_hits: true, body: { docvalue_fields: [ diff --git a/x-pack/plugins/stack_alerts/common/build_sorted_events_query.ts b/x-pack/plugins/stack_alerts/common/build_sorted_events_query.ts index add3e1f59e20e..a4fb54a06ace8 100644 --- a/x-pack/plugins/stack_alerts/common/build_sorted_events_query.ts +++ b/x-pack/plugins/stack_alerts/common/build_sorted_events_query.ts @@ -53,10 +53,10 @@ export const buildSortedEventsQuery = ({ const filterWithTime = [filter, { bool: { filter: rangeFilter } }]; const searchQuery = { - allowNoIndices: true, + allow_no_indices: true, index, size, - ignoreUnavailable: true, + ignore_unavailable: true, track_total_hits: track_total_hits ?? false, body: { docvalue_fields: docFields, diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts index 4adc7c05821f9..66984e46de602 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts @@ -18,6 +18,8 @@ import { getAlertType, ConditionMetAlertInstanceId, ActionGroupId } from './aler import { EsQueryAlertParams, EsQueryAlertState } from './alert_type_params'; import { ActionContext } from './action_context'; import { ESSearchResponse, ESSearchRequest } from '../../../../../../typings/elasticsearch'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; describe('alertType', () => { const logger = loggingSystemMock.create().get(); @@ -132,7 +134,9 @@ describe('alertType', () => { const alertServices: AlertServicesMock = alertsMock.createAlertServices(); const searchResult: ESSearchResponse = generateResults([]); - alertServices.callCluster.mockResolvedValueOnce(searchResult); + alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise(searchResult) + ); const result = await alertType.executor({ alertId: uuid.v4(), @@ -189,7 +193,9 @@ describe('alertType', () => { 'time-field': newestDocumentTimestamp - 2000, }, ]); - alertServices.callCluster.mockResolvedValueOnce(searchResult); + alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise(searchResult) + ); const result = await alertType.executor({ alertId: uuid.v4(), @@ -240,12 +246,14 @@ describe('alertType', () => { const previousTimestamp = Date.now(); const newestDocumentTimestamp = previousTimestamp + 1000; - alertServices.callCluster.mockResolvedValueOnce( - generateResults([ - { - 'time-field': newestDocumentTimestamp, - }, - ]) + alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + generateResults([ + { + 'time-field': newestDocumentTimestamp, + }, + ]) + ) ); const executorOptions = { @@ -300,15 +308,17 @@ describe('alertType', () => { const oldestDocumentTimestamp = Date.now(); - alertServices.callCluster.mockResolvedValueOnce( - generateResults([ - { - 'time-field': oldestDocumentTimestamp, - }, - { - 'time-field': oldestDocumentTimestamp - 1000, - }, - ]) + alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + generateResults([ + { + 'time-field': oldestDocumentTimestamp, + }, + { + 'time-field': oldestDocumentTimestamp - 1000, + }, + ]) + ) ); const result = await alertType.executor({ @@ -359,12 +369,14 @@ describe('alertType', () => { const oldestDocumentTimestamp = Date.now(); - alertServices.callCluster.mockResolvedValueOnce( - generateResults([ - { - 'time-field': oldestDocumentTimestamp, - }, - ]) + alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + generateResults([ + { + 'time-field': oldestDocumentTimestamp, + }, + ]) + ) ); const executorOptions = { @@ -400,15 +412,17 @@ describe('alertType', () => { }); const newestDocumentTimestamp = oldestDocumentTimestamp + 5000; - alertServices.callCluster.mockResolvedValueOnce( - generateResults([ - { - 'time-field': newestDocumentTimestamp, - }, - { - 'time-field': newestDocumentTimestamp - 1000, - }, - ]) + alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + generateResults([ + { + 'time-field': newestDocumentTimestamp, + }, + { + 'time-field': newestDocumentTimestamp - 1000, + }, + ]) + ) ); const secondResult = await alertType.executor({ @@ -443,17 +457,19 @@ describe('alertType', () => { const oldestDocumentTimestamp = Date.now(); - alertServices.callCluster.mockResolvedValueOnce( - generateResults( - [ - { - 'time-field': oldestDocumentTimestamp, - }, - { - 'time-field': oldestDocumentTimestamp - 1000, - }, - ], - true + alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + generateResults( + [ + { + 'time-field': oldestDocumentTimestamp, + }, + { + 'time-field': oldestDocumentTimestamp - 1000, + }, + ], + true + ) ) ); @@ -504,18 +520,20 @@ describe('alertType', () => { const oldestDocumentTimestamp = Date.now(); - alertServices.callCluster.mockResolvedValueOnce( - generateResults( - [ - { - 'time-field': oldestDocumentTimestamp, - }, - { - 'time-field': oldestDocumentTimestamp - 1000, - }, - ], - true, - true + alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( + elasticsearchClientMock.createSuccessTransportRequestPromise( + generateResults( + [ + { + 'time-field': oldestDocumentTimestamp, + }, + { + 'time-field': oldestDocumentTimestamp - 1000, + }, + ], + true, + true + ) ) ); diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts index 7734c59425a16..d1cbeeb46fac0 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts @@ -7,7 +7,6 @@ import { i18n } from '@kbn/i18n'; import { Logger } from 'src/core/server'; -import { ESSearchResponse } from '../../../../../../typings/elasticsearch'; import { AlertType, AlertExecutorOptions } from '../../types'; import { ActionContext, EsQueryAlertActionContext, addMessages } from './action_context'; import { @@ -157,7 +156,7 @@ export function getAlertType( const { alertId, name, services, params, state } = options; const previousTimestamp = state.latestTimestamp; - const callCluster = services.callCluster; + const esClient = services.scopedClusterClient.asCurrentUser; const { parsedQuery, dateStart, dateEnd } = getSearchParams(params); const compareFn = ComparatorFns.get(params.thresholdComparator); @@ -215,7 +214,7 @@ export function getAlertType( logger.debug(`alert ${ES_QUERY_ID}:${alertId} "${name}" query - ${JSON.stringify(query)}`); - const searchResult: ESSearchResponse = await callCluster('search', query); + const { body: searchResult } = await esClient.search(query); if (searchResult.hits.hits.length > 0) { const numMatches = searchResult.hits.total.value; diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts index b86a8f9284c97..a416056217442 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { ILegacyScopedClusterClient } from 'kibana/server'; -import { SearchResponse } from 'elasticsearch'; +import { ElasticsearchClient } from 'kibana/server'; import { Logger } from 'src/core/server'; +import { ApiResponse } from '@elastic/elasticsearch'; +import { SearchResponse } from 'elasticsearch'; import { Query, IIndexPattern, @@ -39,7 +40,7 @@ export async function getShapesFilters( boundaryIndexTitle: string, boundaryGeoField: string, geoField: string, - callCluster: ILegacyScopedClusterClient['callAsCurrentUser'], + esClient: ElasticsearchClient, log: Logger, alertId: string, boundaryNameField?: string, @@ -48,7 +49,8 @@ export async function getShapesFilters( const filters: Record = {}; const shapesIdsNamesMap: Record = {}; // Get all shapes in index - const boundaryData: SearchResponse> = await callCluster('search', { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const { body: boundaryData }: ApiResponse> = await esClient.search({ index: boundaryIndexTitle, body: { size: MAX_SHAPES_QUERY_SIZE, @@ -56,7 +58,7 @@ export async function getShapesFilters( }, }); - boundaryData.hits.hits.forEach(({ _index, _id }) => { + boundaryData.hits.hits.forEach(({ _index, _id }: { _index: string; _id: string }) => { filters[_id] = { geo_shape: { [geoField]: { @@ -101,14 +103,14 @@ export async function executeEsQueryFactory( boundaryNameField?: string; indexQuery?: Query; }, - { callCluster }: { callCluster: ILegacyScopedClusterClient['callAsCurrentUser'] }, + esClient: ElasticsearchClient, log: Logger, shapesFilters: Record ) { return async ( gteDateTime: Date | null, ltDateTime: Date | null - ): Promise | undefined> => { + ): Promise> | undefined> => { let esFormattedQuery; if (indexQuery) { const gteEpochDateTime = gteDateTime ? new Date(gteDateTime).getTime() : null; @@ -192,9 +194,9 @@ export async function executeEsQueryFactory( }, }; - let esResult: SearchResponse | undefined; + let esResult: ApiResponse> | undefined; try { - esResult = await callCluster('search', esQuery); + ({ body: esResult } = await esClient.search(esQuery)); } catch (err) { log.warn(`${err.message}`); } diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts index 3f2421529c346..866b25d239db7 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts @@ -6,8 +6,9 @@ */ import _ from 'lodash'; -import { SearchResponse } from 'elasticsearch'; import { Logger } from 'src/core/server'; +import { ApiResponse } from '@elastic/elasticsearch'; +import { SearchResponse } from 'elasticsearch'; import { executeEsQueryFactory, getShapesFilters, OTHER_CATEGORY } from './es_query_builder'; import { AlertServices } from '../../../../alerting/server'; import { @@ -148,17 +149,22 @@ export const getGeoContainmentExecutor = (log: Logger): GeoContainmentAlertType[ params.boundaryIndexTitle, params.boundaryGeoField, params.geoField, - services.callCluster, + services.scopedClusterClient.asCurrentUser, log, alertId, params.boundaryNameField, params.boundaryIndexQuery ); - const executeEsQuery = await executeEsQueryFactory(params, services, log, shapesFilters); + const executeEsQuery = await executeEsQueryFactory( + params, + services.scopedClusterClient.asCurrentUser, + log, + shapesFilters + ); // Start collecting data only on the first cycle - let currentIntervalResults: SearchResponse | undefined; + let currentIntervalResults: ApiResponse> | undefined; if (!currIntervalStartTime) { log.debug(`alert ${GEO_CONTAINMENT_ID}:${alertId} alert initialized. Collecting data`); // Consider making first time window configurable? @@ -171,7 +177,7 @@ export const getGeoContainmentExecutor = (log: Logger): GeoContainmentAlertType[ } const currLocationMap: Map = transformResults( - currentIntervalResults, + currentIntervalResults?.body, params.dateField, params.geoField ); diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/geo_containment.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/geo_containment.test.ts index 62d95e4ed88d8..429331916ea7d 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/geo_containment.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/geo_containment.test.ts @@ -9,10 +9,10 @@ import _ from 'lodash'; import sampleJsonResponse from './es_sample_response.json'; import sampleJsonResponseWithNesting from './es_sample_response_with_nesting.json'; import { getActiveEntriesAndGenerateAlerts, transformResults } from '../geo_containment'; -import { SearchResponse } from 'elasticsearch'; import { OTHER_CATEGORY } from '../es_query_builder'; import { alertsMock } from '../../../../../alerting/server/mocks'; import { GeoContainmentInstanceContext, GeoContainmentInstanceState } from '../alert_type'; +import { SearchResponse } from 'elasticsearch'; describe('geo_containment', () => { describe('transformResults', () => { diff --git a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.ts b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.ts index d2c910790ea40..4c0fafc95a579 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.ts @@ -146,7 +146,7 @@ export function getAlertType( ); } - const callCluster = services.callCluster; + const esClient = services.scopedClusterClient.asCurrentUser; const date = new Date().toISOString(); // the undefined values below are for config-schema optional types const queryParams: TimeSeriesQuery = { @@ -166,7 +166,7 @@ export function getAlertType( // console.log(`index_threshold: query: ${JSON.stringify(queryParams, null, 4)}`); const result = await (await data).timeSeriesQuery({ logger, - callCluster, + esClient, query: queryParams, }); logger.debug(`alert ${ID}:${alertId} "${name}" query result: ${JSON.stringify(result)}`); diff --git a/x-pack/plugins/triggers_actions_ui/server/data/lib/time_series_query.test.ts b/x-pack/plugins/triggers_actions_ui/server/data/lib/time_series_query.test.ts index fd0ea1bc9e8f5..86d18d98fa0e1 100644 --- a/x-pack/plugins/triggers_actions_ui/server/data/lib/time_series_query.test.ts +++ b/x-pack/plugins/triggers_actions_ui/server/data/lib/time_series_query.test.ts @@ -9,6 +9,8 @@ import { loggingSystemMock } from '../../../../../../src/core/server/mocks'; import { TimeSeriesQueryParameters, TimeSeriesQuery, timeSeriesQuery } from './time_series_query'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { elasticsearchClientMock } from '../../../../../../src/core/server/elasticsearch/client/mocks'; const DefaultQueryParams: TimeSeriesQuery = { index: 'index-name', @@ -27,19 +29,18 @@ const DefaultQueryParams: TimeSeriesQuery = { describe('timeSeriesQuery', () => { let params: TimeSeriesQueryParameters; - const mockCallCluster = jest.fn(); + const esClient = elasticsearchClientMock.createClusterClient().asScoped().asCurrentUser; beforeEach(async () => { - mockCallCluster.mockReset(); params = { logger: loggingSystemMock.create().get(), - callCluster: mockCallCluster, + esClient, query: DefaultQueryParams, }; }); it('fails as expected when the callCluster call fails', async () => { - mockCallCluster.mockRejectedValue(new Error('woopsie')); + esClient.search = jest.fn().mockRejectedValue(new Error('woopsie')); expect(timeSeriesQuery(params)).rejects.toThrowErrorMatchingInlineSnapshot( `"error running search"` ); diff --git a/x-pack/plugins/triggers_actions_ui/server/data/lib/time_series_query.ts b/x-pack/plugins/triggers_actions_ui/server/data/lib/time_series_query.ts index 106f665640e41..78462d9969929 100644 --- a/x-pack/plugins/triggers_actions_ui/server/data/lib/time_series_query.ts +++ b/x-pack/plugins/triggers_actions_ui/server/data/lib/time_series_query.ts @@ -6,8 +6,7 @@ */ import { SearchResponse } from 'elasticsearch'; -import { Logger } from 'kibana/server'; -import { LegacyScopedClusterClient } from '../../../../../../src/core/server'; +import { Logger, ElasticsearchClient } from 'kibana/server'; import { DEFAULT_GROUPS } from '../index'; import { getDateRangeInfo } from './date_range_info'; @@ -16,14 +15,14 @@ export { TimeSeriesQuery, TimeSeriesResult } from './time_series_types'; export interface TimeSeriesQueryParameters { logger: Logger; - callCluster: LegacyScopedClusterClient['callAsCurrentUser']; + esClient: ElasticsearchClient; query: TimeSeriesQuery; } export async function timeSeriesQuery( params: TimeSeriesQueryParameters ): Promise { - const { logger, callCluster, query: queryParams } = params; + const { logger, esClient, query: queryParams } = params; const { index, timeWindowSize, @@ -59,9 +58,8 @@ export async function timeSeriesQuery( }, // aggs: {...}, filled in below }, - ignoreUnavailable: true, - allowNoIndices: true, - ignore: [404], + ignore_unavailable: true, + allow_no_indices: true, }; // add the aggregations @@ -127,17 +125,16 @@ export async function timeSeriesQuery( }; } - let esResult: SearchResponse; const logPrefix = 'indexThreshold timeSeriesQuery: callCluster'; logger.debug(`${logPrefix} call: ${JSON.stringify(esQuery)}`); - + let esResult: SearchResponse; // note there are some commented out console.log()'s below, which are left // in, as they are VERY useful when debugging these queries; debug logging // isn't as nice since it's a single long JSON line. // console.log('time_series_query.ts request\n', JSON.stringify(esQuery, null, 4)); try { - esResult = await callCluster('search', esQuery); + esResult = (await esClient.search>(esQuery, { ignore: [404] })).body; } catch (err) { // console.log('time_series_query.ts error\n', JSON.stringify(err, null, 4)); logger.warn(`${logPrefix} error: ${err.message}`); 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 e5cafdd8a0ad7..6a3b5a0c44aba 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 @@ -12,7 +12,7 @@ import { KibanaRequest, IKibanaResponse, KibanaResponseFactory, - ILegacyScopedClusterClient, + ElasticsearchClient, } from 'kibana/server'; import { Logger } from '../../../../../../src/core/server'; @@ -49,7 +49,10 @@ export function createFieldsRoute(logger: Logger, router: IRouter, baseRoute: st } try { - rawFields = await getRawFields(ctx.core.elasticsearch.legacy.client, req.body.indexPatterns); + rawFields = await getRawFields( + ctx.core.elasticsearch.client.asCurrentUser, + req.body.indexPatterns + ); } catch (err) { const indexPatterns = req.body.indexPatterns.join(','); logger.warn( @@ -90,19 +93,15 @@ interface Field { aggregatable: boolean; } -async function getRawFields( - dataClient: ILegacyScopedClusterClient, - indexes: string[] -): Promise { +async function getRawFields(esClient: ElasticsearchClient, indexes: string[]): Promise { const params = { index: indexes, fields: ['*'], - ignoreUnavailable: true, - allowNoIndices: true, - ignore: 404, + ignore_unavailable: true, + allow_no_indices: true, }; - const result = await dataClient.callAsCurrentUser('fieldCaps', params); - return result as RawFields; + const result = await esClient.fieldCaps(params); + return result.body as RawFields; } function getFieldsFromRawFields(rawFields: RawFields): Field[] { diff --git a/x-pack/plugins/triggers_actions_ui/server/data/routes/indices.ts b/x-pack/plugins/triggers_actions_ui/server/data/routes/indices.ts index 13d6892f37c1b..c029f5b8bdaed 100644 --- a/x-pack/plugins/triggers_actions_ui/server/data/routes/indices.ts +++ b/x-pack/plugins/triggers_actions_ui/server/data/routes/indices.ts @@ -17,9 +17,8 @@ import { KibanaRequest, IKibanaResponse, KibanaResponseFactory, - ILegacyScopedClusterClient, + ElasticsearchClient, } from 'kibana/server'; -import { SearchResponse } from 'elasticsearch'; import { Logger } from '../../../../../../src/core/server'; const bodySchema = schema.object({ @@ -54,14 +53,14 @@ export function createIndicesRoute(logger: Logger, router: IRouter, baseRoute: s let aliases: string[] = []; try { - aliases = await getAliasesFromPattern(ctx.core.elasticsearch.legacy.client, pattern); + aliases = await getAliasesFromPattern(ctx.core.elasticsearch.client.asCurrentUser, pattern); } catch (err) { logger.warn(`route ${path} error getting aliases from pattern "${pattern}": ${err.message}`); } let indices: string[] = []; try { - indices = await getIndicesFromPattern(ctx.core.elasticsearch.legacy.client, pattern); + indices = await getIndicesFromPattern(ctx.core.elasticsearch.client.asCurrentUser, pattern); } catch (err) { logger.warn(`route ${path} error getting indices from pattern "${pattern}": ${err.message}`); } @@ -81,13 +80,12 @@ function uniqueCombined(list1: string[], list2: string[], limit: number) { } async function getIndicesFromPattern( - dataClient: ILegacyScopedClusterClient, + esClient: ElasticsearchClient, pattern: string ): Promise { const params = { index: pattern, - ignore: [404], - ignoreUnavailable: true, + ignore_unavailable: true, body: { size: 0, // no hits aggs: { @@ -100,7 +98,7 @@ async function getIndicesFromPattern( }, }, }; - const response: SearchResponse = await dataClient.callAsCurrentUser('search', params); + const { body: response } = await esClient.search(params); // TODO: Investigate when the status field might appear here, type suggests it shouldn't ever happen // eslint-disable-next-line @typescript-eslint/no-explicit-any if ((response as any).status === 404 || !response.aggregations) { @@ -111,17 +109,16 @@ async function getIndicesFromPattern( } async function getAliasesFromPattern( - dataClient: ILegacyScopedClusterClient, + esClient: ElasticsearchClient, pattern: string ): Promise { const params = { index: pattern, - ignoreUnavailable: true, - ignore: [404], + ignore_unavailable: true, }; const result: string[] = []; - const response = await dataClient.callAsCurrentUser('indices.getAlias', params); + const { body: response } = await esClient.indices.getAlias(params); if (response.status === 404) { return result; diff --git a/x-pack/plugins/triggers_actions_ui/server/data/routes/time_series_query.ts b/x-pack/plugins/triggers_actions_ui/server/data/routes/time_series_query.ts index dc94d56623bba..da6638db2e457 100644 --- a/x-pack/plugins/triggers_actions_ui/server/data/routes/time_series_query.ts +++ b/x-pack/plugins/triggers_actions_ui/server/data/routes/time_series_query.ts @@ -44,7 +44,7 @@ export function createTimeSeriesQueryRoute( const result = await timeSeriesQuery({ logger, - callCluster: ctx.core.elasticsearch.legacy.client.callAsCurrentUser, + esClient: ctx.core.elasticsearch.client.asCurrentUser, query: req.body, }); diff --git a/x-pack/plugins/uptime/server/lib/alerts/status_check.test.ts b/x-pack/plugins/uptime/server/lib/alerts/status_check.test.ts index 12db6eeff8fcf..29f2f0cca82bc 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/status_check.test.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/status_check.test.ts @@ -27,6 +27,7 @@ import { GetMonitorStatusResult } from '../requests/get_monitor_status'; import { makePing } from '../../../common/runtime_types/ping'; import { GetMonitorAvailabilityResult } from '../requests/get_monitor_availability'; import type { UptimeRouter } from '../../types'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; /** * The alert takes some dependencies as parameters; these are things like @@ -63,7 +64,8 @@ const mockOptions = ( services = alertsMock.createAlertServices(), state = {} ): any => { - services.scopedClusterClient = jest.fn() as any; + services.scopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); + services.scopedClusterClient.asCurrentUser = (jest.fn() as unknown) as any; services.savedObjectsClient.get.mockResolvedValue({ id: '', diff --git a/x-pack/plugins/uptime/server/lib/alerts/uptime_alert_wrapper.ts b/x-pack/plugins/uptime/server/lib/alerts/uptime_alert_wrapper.ts index 97e8b0614a354..654f99cb0265a 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/uptime_alert_wrapper.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/uptime_alert_wrapper.ts @@ -58,7 +58,10 @@ export const uptimeAlertWrapper = ( options.services.savedObjectsClient ); - const uptimeEsClient = createUptimeESClient({ esClient, savedObjectsClient }); + const uptimeEsClient = createUptimeESClient({ + esClient: esClient.asCurrentUser, + savedObjectsClient, + }); return uptimeAlert.executor({ options, dynamicSettings, uptimeEsClient, savedObjectsClient }); }, diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts index 1847b3fbbce2a..59efbaf24d9e0 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts @@ -132,7 +132,7 @@ async function alwaysFiringExecutor(alertExecutorOptions: any) { } } - await services.scopedClusterClient.index({ + await services.scopedClusterClient.asCurrentUser.index({ index: params.index, refresh: 'wait_for', body: { @@ -212,7 +212,7 @@ function getNeverFiringAlertType() { defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', async executor({ services, params, state }) { - await services.callCluster('index', { + await services.scopedClusterClient.asCurrentUser.index({ index: params.index, refresh: 'wait_for', body: { @@ -252,7 +252,7 @@ function getFailingAlertType() { defaultActionGroupId: 'default', minimumLicenseRequired: 'basic', async executor({ services, params, state }) { - await services.callCluster('index', { + await services.scopedClusterClient.asCurrentUser.index({ index: params.index, refresh: 'wait_for', body: { @@ -269,7 +269,6 @@ function getFailingAlertType() { } function getAuthorizationAlertType(core: CoreSetup) { - const clusterClient = core.elasticsearch.legacy.client; const paramsSchema = schema.object({ callClusterAuthorizationIndex: schema.string(), savedObjectsClientType: schema.string(), @@ -298,7 +297,7 @@ function getAuthorizationAlertType(core: CoreSetup) { let callClusterSuccess = false; let callClusterError; try { - await services.callCluster('index', { + await services.scopedClusterClient.asCurrentUser.index({ index: params.callClusterAuthorizationIndex, refresh: 'wait_for', body: { @@ -310,11 +309,11 @@ function getAuthorizationAlertType(core: CoreSetup) { callClusterError = e; } // Call scoped cluster - const scopedClusterClient = services.getLegacyScopedClusterClient(clusterClient); + const scopedClusterClient = services.scopedClusterClient; let callScopedClusterSuccess = false; let callScopedClusterError; try { - await scopedClusterClient.callAsCurrentUser('index', { + await scopedClusterClient.asCurrentUser.index({ index: params.callClusterAuthorizationIndex, refresh: 'wait_for', body: { @@ -338,7 +337,7 @@ function getAuthorizationAlertType(core: CoreSetup) { savedObjectsClientError = e; } // Save the result - await services.callCluster('index', { + await services.scopedClusterClient.asCurrentUser.index({ index: params.index, refresh: 'wait_for', body: { @@ -417,7 +416,7 @@ function getPatternFiringAlertType() { } if (params.reference) { - await services.scopedClusterClient.index({ + await services.scopedClusterClient.asCurrentUser.index({ index: ES_TEST_INDEX_NAME, refresh: 'wait_for', body: { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts index 05060a2fcf7a9..536c4cbbd710f 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/alerts.ts @@ -533,11 +533,9 @@ instanceStateValue: true savedObjectsClientSuccess: false, callClusterError: { ...searchResult.hits.hits[0]._source.state.callClusterError, - statusCode: 403, }, callScopedClusterError: { ...searchResult.hits.hits[0]._source.state.callScopedClusterError, - statusCode: 403, }, savedObjectsClientError: { ...searchResult.hits.hits[0]._source.state.savedObjectsClientError,