diff --git a/src/plugins/presentation_util/common/labs.ts b/src/plugins/presentation_util/common/labs.ts index 7ca5272daa9c..d80624fe0bb9 100644 --- a/src/plugins/presentation_util/common/labs.ts +++ b/src/plugins/presentation_util/common/labs.ts @@ -9,11 +9,10 @@ import { i18n } from '@kbn/i18n'; export const LABS_PROJECT_PREFIX = 'labs:'; -export const USE_DATA_SERVICE = `${LABS_PROJECT_PREFIX}canvas:useDataService` as const; export const TIME_TO_PRESENT = `${LABS_PROJECT_PREFIX}presentation:timeToPresent` as const; export const DEFER_BELOW_FOLD = `${LABS_PROJECT_PREFIX}dashboard:deferBelowFold` as const; -export const projectIDs = [TIME_TO_PRESENT, USE_DATA_SERVICE, DEFER_BELOW_FOLD] as const; +export const projectIDs = [TIME_TO_PRESENT, DEFER_BELOW_FOLD] as const; export const environmentNames = ['kibana', 'browser', 'session'] as const; export const solutionNames = ['canvas', 'dashboard', 'presentation'] as const; @@ -35,22 +34,6 @@ export const projects: { [ID in ProjectID]: ProjectConfig & { id: ID } } = { }), solutions: ['canvas'], }, - [USE_DATA_SERVICE]: { - id: USE_DATA_SERVICE, - isActive: true, - isDisplayed: true, - environments: ['kibana', 'browser', 'session'], - name: i18n.translate('presentationUtil.experiments.enableUseDataServiceExperimentName', { - defaultMessage: 'Use data service', - }), - description: i18n.translate( - 'presentationUtil.experiments.enableUseDataServiceExperimentDescription', - { - defaultMessage: 'An experiment of using the new data.search service for Canvas datasources', - } - ), - solutions: ['canvas'], - }, [DEFER_BELOW_FOLD]: { id: DEFER_BELOW_FOLD, isActive: false, diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/escount.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/escount.ts deleted file mode 100644 index 95f5ef446a47..000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/escount.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - ExpressionFunctionDefinition, - ExpressionValueFilter, -} from 'src/plugins/expressions/common'; -// @ts-expect-error untyped local -import { buildESRequest } from '../../../common/lib/request/build_es_request'; - -import { getFunctionHelp } from '../../../i18n'; - -interface Arguments { - index: string | null; - query: string; -} - -export function escount(): ExpressionFunctionDefinition< - 'escount', - ExpressionValueFilter, - Arguments, - any -> { - const { help, args: argHelp } = getFunctionHelp().escount; - - return { - name: 'escount', - type: 'number', - context: { - types: ['filter'], - }, - help, - args: { - query: { - types: ['string'], - aliases: ['_', 'q'], - help: argHelp.query, - default: '"-_index:.kibana"', - }, - index: { - types: ['string'], - default: '_all', - help: argHelp.index, - }, - }, - fn: (input, args, handlers) => { - input.and = input.and.concat([ - { - type: 'filter', - filterType: 'luceneQueryString', - query: args.query, - and: [], - }, - ]); - - const esRequest = buildESRequest( - { - index: args.index, - body: { - query: { - bool: { - must: [{ match_all: {} }], - }, - }, - }, - }, - input - ); - - return ((handlers as any) as { elasticsearchClient: any }) - .elasticsearchClient('count', esRequest) - .then((resp: { count: number }) => resp.count); - }, - }; -} diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/esdocs.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/esdocs.ts deleted file mode 100644 index e77717d689f9..000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/esdocs.ts +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import squel from 'safe-squel'; -import { ExpressionFunctionDefinition } from 'src/plugins/expressions'; -/* eslint-disable */ -import { queryEsSQL } from '../../../server/lib/query_es_sql'; -/* eslint-enable */ -import { ExpressionValueFilter } from '../../../types'; -import { getFunctionHelp } from '../../../i18n'; - -interface Arguments { - index: string; - query: string; - sort: string; - fields: string; - metaFields: string; - count: number; -} - -export function esdocs(): ExpressionFunctionDefinition< - 'esdocs', - ExpressionValueFilter, - Arguments, - any -> { - const { help, args: argHelp } = getFunctionHelp().esdocs; - - return { - name: 'esdocs', - type: 'datatable', - context: { - types: ['filter'], - }, - help, - args: { - query: { - types: ['string'], - aliases: ['_', 'q'], - help: argHelp.query, - default: '-_index:.kibana', - }, - count: { - types: ['number'], - default: 1000, - help: argHelp.count, - }, - fields: { - help: argHelp.fields, - types: ['string'], - }, - index: { - types: ['string'], - default: '_all', - help: argHelp.index, - }, - // TODO: This arg isn't being used in the function. - // We need to restore this functionality or remove it as an arg. - metaFields: { - help: argHelp.metaFields, - types: ['string'], - }, - sort: { - types: ['string'], - help: argHelp.sort, - }, - }, - fn: (input, args, context) => { - const { count, index, fields, sort } = args; - - input.and = input.and.concat([ - { - type: 'filter', - filterType: 'luceneQueryString', - query: args.query, - and: [], - }, - ]); - - let query = squel.select({ - autoQuoteTableNames: true, - autoQuoteFieldNames: true, - autoQuoteAliasNames: true, - nameQuoteCharacter: '"', - }); - - if (index) { - query.from(index); - } - - if (fields) { - const allFields = fields.split(',').map((field) => field.trim()); - allFields.forEach((field) => (query = query.field(field))); - } - - if (sort) { - const [sortField, sortOrder] = sort.split(',').map((str) => str.trim()); - if (sortField) { - query.order(`"${sortField}"`, sortOrder === 'asc'); - } - } - - return queryEsSQL(((context as any) as { elasticsearchClient: any }).elasticsearchClient, { - count, - query: query.toString(), - filter: input.and, - }); - }, - }; -} diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/essql.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/essql.ts deleted file mode 100644 index d14a8c0bec76..000000000000 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/essql.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ExpressionFunctionDefinition } from 'src/plugins/expressions/common'; -/* eslint-disable */ -import { queryEsSQL } from '../../../server/lib/query_es_sql'; -/* eslint-enable */ -import { ExpressionValueFilter } from '../../../types'; -import { getFunctionHelp } from '../../../i18n'; - -interface Arguments { - query: string; - count: number; - timezone: string; -} - -export function essql(): ExpressionFunctionDefinition< - 'essql', - ExpressionValueFilter, - Arguments, - any -> { - const { help, args: argHelp } = getFunctionHelp().essql; - - return { - name: 'essql', - type: 'datatable', - context: { - types: ['filter'], - }, - help, - args: { - query: { - aliases: ['_', 'q'], - types: ['string'], - help: argHelp.query, - }, - count: { - types: ['number'], - help: argHelp.count, - default: 1000, - }, - timezone: { - aliases: ['tz'], - types: ['string'], - default: 'UTC', - help: argHelp.timezone, - }, - }, - fn: (input, args, context) => { - return queryEsSQL(((context as any) as { elasticsearchClient: any }).elasticsearchClient, { - ...args, - filter: input.and, - }); - }, - }; -} diff --git a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/index.ts b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/index.ts index e9731448f65b..ae3778366651 100644 --- a/x-pack/plugins/canvas/canvas_plugin_src/functions/server/index.ts +++ b/x-pack/plugins/canvas/canvas_plugin_src/functions/server/index.ts @@ -6,9 +6,6 @@ */ import { demodata } from './demodata'; -import { escount } from './escount'; -import { esdocs } from './esdocs'; import { pointseries } from './pointseries'; -import { essql } from './essql'; -export const functions = [demodata, esdocs, escount, essql, pointseries]; +export const functions = [demodata, pointseries]; diff --git a/x-pack/plugins/canvas/public/services/expressions.ts b/x-pack/plugins/canvas/public/services/expressions.ts index 35493341e0e8..219edb667efc 100644 --- a/x-pack/plugins/canvas/public/services/expressions.ts +++ b/x-pack/plugins/canvas/public/services/expressions.ts @@ -24,10 +24,6 @@ export const expressionsServiceFactory: CanvasServiceFactory const loadServerFunctionWrappers = async () => { if (!cached) { cached = (async () => { - const labService = startPlugins.presentationUtil.labsService; - const hasDataSearch = labService.isProjectEnabled('labs:canvas:useDataService'); - const dataSearchFns = ['essql', 'esdocs', 'escount']; - const serverFunctionList = await coreSetup.http.get(API_ROUTE_FUNCTIONS); const batchedFunction = bfetch.batchedFunction({ url: API_ROUTE_FUNCTIONS }); const { serialize } = serializeProvider(expressions.getTypes()); @@ -36,13 +32,7 @@ export const expressionsServiceFactory: CanvasServiceFactory // function that matches its definition, but which simply // calls the server-side function endpoint. Object.keys(serverFunctionList).forEach((functionName) => { - // Allow function to be overwritten if we want to use - // the server-hosted essql, esdocs, and escount functions - if (dataSearchFns.includes(functionName)) { - if (hasDataSearch && expressions.getFunction(functionName)) { - return; - } - } else if (expressions.getFunction(functionName)) { + if (expressions.getFunction(functionName)) { return; } diff --git a/x-pack/plugins/canvas/server/lib/essql_strategy.test.ts b/x-pack/plugins/canvas/server/lib/essql_strategy.test.ts new file mode 100644 index 000000000000..7ef543e848ad --- /dev/null +++ b/x-pack/plugins/canvas/server/lib/essql_strategy.test.ts @@ -0,0 +1,165 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { essqlSearchStrategyProvider } from './essql_strategy'; +import { EssqlSearchStrategyRequest } from '../../types'; +import { zipObject } from 'lodash'; + +const getMockEssqlResponse = () => ({ + body: { + columns: [ + { name: 'One', type: 'keyword' }, + { name: 'Two', type: 'keyword' }, + ], + rows: [ + ['foo', 'bar'], + ['buz', 'baz'], + ['beep', 'boop'], + ], + cursor: 'cursor-value', + }, + statusCode: 200, +}); + +const basicReq: EssqlSearchStrategyRequest = { + query: 'SELECT * FROM my_index;', + count: 3, + params: ['my_var'], + filter: [ + { + type: 'filter', + filterType: 'exactly', + value: 'Test Value', + column: 'One', + and: [], + }, + ], + timezone: 'UTC', +}; + +describe('ESSQL search strategy', () => { + describe('strategy interface', () => { + it('returns a strategy with a `search` function', async () => { + const essqlSearch = await essqlSearchStrategyProvider(); + expect(typeof essqlSearch.search).toBe('function'); + }); + }); + + describe('search()', () => { + let mockQuery: jest.Mock; + let mockClearCursor: jest.Mock; + let mockDeps: any; + + beforeEach(() => { + mockQuery = jest.fn().mockResolvedValueOnce(getMockEssqlResponse()); + mockClearCursor = jest.fn(); + mockDeps = ({ + esClient: { + asCurrentUser: { + sql: { + query: mockQuery, + clearCursor: mockClearCursor, + }, + }, + }, + } as unknown) as any; + }); + + describe('query functionality', () => { + it('performs a simple query', async () => { + const sqlSearch = await essqlSearchStrategyProvider(); + const result = await sqlSearch.search(basicReq, {}, mockDeps).toPromise(); + const [[request]] = mockQuery.mock.calls; + + expect(request.format).toEqual('json'); + expect(request.body).toEqual( + expect.objectContaining({ + query: basicReq.query, + client_id: 'canvas', + fetch_size: basicReq.count, + time_zone: basicReq.timezone, + field_multi_value_leniency: true, + params: ['my_var'], + }) + ); + + const expectedColumns = getMockEssqlResponse().body.columns.map((c) => ({ + id: c.name, + name: c.name, + meta: { type: 'string' }, + })); + const columnNames = expectedColumns.map((c) => c.name); + const expectedRows = getMockEssqlResponse().body.rows.map((r) => zipObject(columnNames, r)); + + expect(result.columns).toEqual(expectedColumns); + expect(result.rows).toEqual(expectedRows); + }); + + it('iterates over cursor to retrieve for records query', async () => { + const pageOne = { + body: { + columns: [ + { name: 'One', type: 'keyword' }, + { name: 'Two', type: 'keyword' }, + ], + rows: [['foo', 'bar']], + cursor: 'cursor-value', + }, + }; + + const pageTwo = { + body: { + rows: [['buz', 'baz']], + }, + }; + + mockQuery.mockReset().mockReturnValueOnce(pageOne).mockReturnValueOnce(pageTwo); + + const sqlSearch = await essqlSearchStrategyProvider(); + const result = await sqlSearch.search({ ...basicReq, count: 2 }, {}, mockDeps).toPromise(); + + expect(result.rows).toHaveLength(2); + }); + + it('closes any cursors that remain open', async () => { + const sqlSearch = await essqlSearchStrategyProvider(); + await sqlSearch.search(basicReq, {}, mockDeps).toPromise(); + + const [[cursorReq]] = mockClearCursor.mock.calls; + expect(cursorReq.body.cursor).toEqual('cursor-value'); + }); + + it('emits an error if the client throws', async () => { + const req: EssqlSearchStrategyRequest = { + query: 'SELECT * FROM my_index;', + count: 1, + params: [], + filter: [ + { + type: 'filter', + filterType: 'exactly', + value: 'Test Value', + column: 'category.keyword', + and: [], + }, + ], + timezone: 'UTC', + }; + + expect.assertions(1); + mockQuery.mockReset().mockRejectedValueOnce(new Error('client error')); + const eqlSearch = await essqlSearchStrategyProvider(); + eqlSearch.search(req, {}, mockDeps).subscribe( + () => {}, + (err) => { + expect(err).toEqual(new Error('client error')); + } + ); + }); + }); + }); +}); diff --git a/x-pack/plugins/canvas/server/lib/essql_strategy.ts b/x-pack/plugins/canvas/server/lib/essql_strategy.ts index 795b4fedaaaa..273ffb53b0ed 100644 --- a/x-pack/plugins/canvas/server/lib/essql_strategy.ts +++ b/x-pack/plugins/canvas/server/lib/essql_strategy.ts @@ -8,7 +8,7 @@ import { from } from 'rxjs'; import { map, zipObject } from 'lodash'; -import { ISearchStrategy, PluginStart } from 'src/plugins/data/server'; +import { ISearchStrategy } from 'src/plugins/data/server'; import { getKbnServerError } from '../../../../../src/plugins/kibana_utils/server'; import { EssqlSearchStrategyRequest, EssqlSearchStrategyResponse } from '../../types'; @@ -17,9 +17,10 @@ import { buildBoolArray } from '../../common/lib/request/build_bool_array'; import { sanitizeName } from '../../common/lib/request/sanitize_name'; import { normalizeType } from '../../common/lib/request/normalize_type'; -export const essqlSearchStrategyProvider = ( - data: PluginStart -): ISearchStrategy => { +export const essqlSearchStrategyProvider = (): ISearchStrategy< + EssqlSearchStrategyRequest, + EssqlSearchStrategyResponse +> => { return { search: (request, options, { esClient }) => { const { count, query, filter, timezone, params } = request; diff --git a/x-pack/plugins/canvas/server/lib/query_es_sql.test.ts b/x-pack/plugins/canvas/server/lib/query_es_sql.test.ts deleted file mode 100644 index 5c07f70579f8..000000000000 --- a/x-pack/plugins/canvas/server/lib/query_es_sql.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { zipObject } from 'lodash'; -import { queryEsSQL } from './query_es_sql'; -// @ts-expect-error -import { buildBoolArray } from './build_bool_array'; - -const response = { - columns: [ - { name: 'One', type: 'keyword' }, - { name: 'Two', type: 'keyword' }, - ], - rows: [ - ['foo', 'bar'], - ['buz', 'baz'], - ], - cursor: 'cursor-value', -}; - -const baseArgs = { - count: 1, - query: 'query', - filter: [], - timezone: 'timezone', -}; - -const getApi = (resp = response) => { - const api = jest.fn(); - api.mockResolvedValue(resp); - return api; -}; - -describe('query_es_sql', () => { - it('should call the api with the given args', async () => { - const api = getApi(); - - queryEsSQL(api, baseArgs); - - expect(api).toHaveBeenCalled(); - const givenArgs = api.mock.calls[0][1]; - - expect(givenArgs.body.fetch_size).toBe(baseArgs.count); - expect(givenArgs.body.query).toBe(baseArgs.query); - expect(givenArgs.body.time_zone).toBe(baseArgs.timezone); - }); - - it('formats the response', async () => { - const api = getApi(); - - const result = await queryEsSQL(api, baseArgs); - - const expectedColumns = response.columns.map((c) => ({ - id: c.name, - name: c.name, - meta: { type: 'string' }, - })); - const columnNames = expectedColumns.map((c) => c.name); - const expectedRows = response.rows.map((r) => zipObject(columnNames, r)); - - expect(result.type).toBe('datatable'); - expect(result.columns).toEqual(expectedColumns); - expect(result.rows).toEqual(expectedRows); - }); - - it('fetches pages until it has the requested count', async () => { - const pageOne = { - columns: [ - { name: 'One', type: 'keyword' }, - { name: 'Two', type: 'keyword' }, - ], - rows: [['foo', 'bar']], - cursor: 'cursor-value', - }; - - const pageTwo = { - rows: [['buz', 'baz']], - }; - - const api = getApi(pageOne); - api.mockReturnValueOnce(pageOne).mockReturnValueOnce(pageTwo); - - const result = await queryEsSQL(api, { ...baseArgs, count: 2 }); - expect(result.rows).toHaveLength(2); - }); - - it('closes any cursors that remain open', async () => { - const api = getApi(); - - await queryEsSQL(api, baseArgs); - expect(api.mock.calls[1][1].body.cursor).toBe(response.cursor); - }); - - it('throws on errors', async () => { - const api = getApi(); - api.mockRejectedValueOnce(new Error('parsing_exception')); - api.mockRejectedValueOnce(new Error('generic es error')); - - expect(queryEsSQL(api, baseArgs)).rejects.toThrowErrorMatchingInlineSnapshot( - `"Couldn't parse Elasticsearch SQL query. You may need to add double quotes to names containing special characters. Check your query and try again. Error: parsing_exception"` - ); - - expect(queryEsSQL(api, baseArgs)).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unexpected error from Elasticsearch: generic es error"` - ); - }); -}); diff --git a/x-pack/plugins/canvas/server/lib/query_es_sql.ts b/x-pack/plugins/canvas/server/lib/query_es_sql.ts deleted file mode 100644 index 2c4416094914..000000000000 --- a/x-pack/plugins/canvas/server/lib/query_es_sql.ts +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { map, zipObject } from 'lodash'; -import { buildBoolArray } from '../../common/lib/request/build_bool_array'; -import { sanitizeName } from '../../common/lib/request/sanitize_name'; -import { normalizeType } from '../../common/lib/request/normalize_type'; -import { LegacyAPICaller } from '../../../../../src/core/server'; -import { ExpressionValueFilter } from '../../types'; - -interface Args { - count: number; - query: string; - timezone?: string; - filter: ExpressionValueFilter[]; -} - -interface CursorResponse { - cursor?: string; - rows: string[][]; -} - -type QueryResponse = CursorResponse & { - columns: Array<{ - name: string; - type: string; - }>; - cursor?: string; - rows: string[][]; -}; - -export const queryEsSQL = async ( - elasticsearchClient: LegacyAPICaller, - { count, query, filter, timezone }: Args -) => { - try { - let response: QueryResponse = await elasticsearchClient('transport.request', { - path: '/_sql?format=json', - method: 'POST', - body: { - query, - time_zone: timezone, - fetch_size: count, - client_id: 'canvas', - filter: { - bool: { - must: [{ match_all: {} }, ...buildBoolArray(filter)], - }, - }, - }, - }); - - const columns = response.columns.map(({ name, type }) => { - return { - id: sanitizeName(name), - name: sanitizeName(name), - meta: { type: normalizeType(type) }, - }; - }); - const columnNames = map(columns, 'name'); - let rows = response.rows.map((row) => zipObject(columnNames, row)); - - while (rows.length < count && response.cursor !== undefined) { - response = await elasticsearchClient('transport.request', { - path: '/_sql?format=json', - method: 'POST', - body: { - cursor: response.cursor, - }, - }); - - rows = [...rows, ...response.rows.map((row) => zipObject(columnNames, row))]; - } - - if (response.cursor !== undefined) { - elasticsearchClient('transport.request', { - path: '/_sql/close', - method: 'POST', - body: { - cursor: response.cursor, - }, - }); - } - - return { - type: 'datatable', - meta: { - type: 'essql', - }, - columns, - rows, - }; - } catch (e) { - if (e.message.indexOf('parsing_exception') > -1) { - throw new Error( - `Couldn't parse Elasticsearch SQL query. You may need to add double quotes to names containing special characters. Check your query and try again. Error: ${e.message}` - ); - } - throw new Error(`Unexpected error from Elasticsearch: ${e.message}`); - } -}; diff --git a/x-pack/plugins/canvas/server/plugin.ts b/x-pack/plugins/canvas/server/plugin.ts index 9ccf3c251fec..f0b7c0243000 100644 --- a/x-pack/plugins/canvas/server/plugin.ts +++ b/x-pack/plugins/canvas/server/plugin.ts @@ -61,7 +61,6 @@ export class CanvasPlugin implements Plugin { router: canvasRouter, expressions: plugins.expressions, bfetch: plugins.bfetch, - elasticsearch: coreSetup.elasticsearch, logger: this.logger, }); @@ -77,7 +76,7 @@ export class CanvasPlugin implements Plugin { setupInterpreter(plugins.expressions); coreSetup.getStartServices().then(([_, depsStart]) => { - const strategy = essqlSearchStrategyProvider(depsStart.data); + const strategy = essqlSearchStrategyProvider(); plugins.data.search.registerSearchStrategy(ESSQL_SEARCH_STRATEGY, strategy); }); } diff --git a/x-pack/plugins/canvas/server/routes/es_fields/es_fields.test.ts b/x-pack/plugins/canvas/server/routes/es_fields/es_fields.test.ts index 1e95ee809e76..02d7e9ca2e26 100644 --- a/x-pack/plugins/canvas/server/routes/es_fields/es_fields.test.ts +++ b/x-pack/plugins/canvas/server/routes/es_fields/es_fields.test.ts @@ -13,7 +13,7 @@ import { getMockedRouterDeps } from '../test_helpers'; const mockRouteContext = ({ core: { elasticsearch: { - legacy: { client: elasticsearchServiceMock.createLegacyScopedClusterClient() }, + client: elasticsearchServiceMock.createScopedClusterClient(), }, }, } as unknown) as RequestHandlerContext; @@ -33,27 +33,29 @@ describe('Retrieve ES Fields', () => { it(`returns 200 with fields from existing index/index pattern`, async () => { const index = 'test'; const mockResults = { - indices: ['test'], - fields: { - '@timestamp': { - date: { - type: 'date', - searchable: true, - aggregatable: true, + body: { + indices: ['test'], + fields: { + '@timestamp': { + date: { + type: 'date', + searchable: true, + aggregatable: true, + }, }, - }, - name: { - text: { - type: 'text', - searchable: true, - aggregatable: false, + name: { + text: { + type: 'text', + searchable: true, + aggregatable: false, + }, }, - }, - products: { - object: { - type: 'object', - searchable: false, - aggregatable: false, + products: { + object: { + type: 'object', + searchable: false, + aggregatable: false, + }, }, }, }, @@ -66,10 +68,10 @@ describe('Retrieve ES Fields', () => { }, }); - const callAsCurrentUserMock = mockRouteContext.core.elasticsearch.legacy.client - .callAsCurrentUser as jest.Mock; + const fieldCapsMock = mockRouteContext.core.elasticsearch.client.asCurrentUser + .fieldCaps as jest.Mock; - callAsCurrentUserMock.mockResolvedValueOnce(mockResults); + fieldCapsMock.mockResolvedValueOnce(mockResults); const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); @@ -85,7 +87,7 @@ describe('Retrieve ES Fields', () => { it(`returns 200 with empty object when index/index pattern has no fields`, async () => { const index = 'test'; - const mockResults = { indices: [index], fields: {} }; + const mockResults = { body: { indices: [index], fields: {} } }; const request = httpServerMock.createKibanaRequest({ method: 'get', path, @@ -94,10 +96,10 @@ describe('Retrieve ES Fields', () => { }, }); - const callAsCurrentUserMock = mockRouteContext.core.elasticsearch.legacy.client - .callAsCurrentUser as jest.Mock; + const fieldCapsMock = mockRouteContext.core.elasticsearch.client.asCurrentUser + .fieldCaps as jest.Mock; - callAsCurrentUserMock.mockResolvedValueOnce(mockResults); + fieldCapsMock.mockResolvedValueOnce(mockResults); const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); @@ -109,8 +111,10 @@ describe('Retrieve ES Fields', () => { const index = 'test'; const mockResults = { - indices: [index], - fields: {}, + body: { + indices: [index], + fields: {}, + }, }; const request = httpServerMock.createKibanaRequest({ @@ -122,10 +126,10 @@ describe('Retrieve ES Fields', () => { }, }); - const callAsCurrentUserMock = mockRouteContext.core.elasticsearch.legacy.client - .callAsCurrentUser as jest.Mock; + const fieldCapsMock = mockRouteContext.core.elasticsearch.client.asCurrentUser + .fieldCaps as jest.Mock; - callAsCurrentUserMock.mockResolvedValueOnce(mockResults); + fieldCapsMock.mockResolvedValueOnce(mockResults); const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); @@ -142,10 +146,10 @@ describe('Retrieve ES Fields', () => { }, }); - const callAsCurrentUserMock = mockRouteContext.core.elasticsearch.legacy.client - .callAsCurrentUser as jest.Mock; + const fieldCapsMock = mockRouteContext.core.elasticsearch.client.asCurrentUser + .fieldCaps as jest.Mock; - callAsCurrentUserMock.mockRejectedValueOnce(new Error('Index not found')); + fieldCapsMock.mockRejectedValueOnce(new Error('Index not found')); await expect( routeHandler(mockRouteContext, request, kibanaResponseFactory) diff --git a/x-pack/plugins/canvas/server/routes/es_fields/es_fields.ts b/x-pack/plugins/canvas/server/routes/es_fields/es_fields.ts index 20a4775847c9..340a6cdb902f 100644 --- a/x-pack/plugins/canvas/server/routes/es_fields/es_fields.ts +++ b/x-pack/plugins/canvas/server/routes/es_fields/es_fields.ts @@ -28,7 +28,7 @@ export function initializeESFieldsRoute(deps: RouteInitializerDeps) { }, }, catchErrorHandler(async (context, request, response) => { - const { callAsCurrentUser } = context.core.elasticsearch.legacy.client; + const client = context.core.elasticsearch.client.asCurrentUser; const { index, fields } = request.query; const config = { @@ -36,8 +36,8 @@ export function initializeESFieldsRoute(deps: RouteInitializerDeps) { fields: fields || '*', }; - const esFields = await callAsCurrentUser('fieldCaps', config).then((resp) => { - return mapValues(resp.fields, (types) => { + const esFields = await client.fieldCaps(config).then((resp) => { + return mapValues(resp.body.fields, (types) => { if (keys(types).length > 1) { return 'conflict'; } diff --git a/x-pack/plugins/canvas/server/routes/functions/functions.ts b/x-pack/plugins/canvas/server/routes/functions/functions.ts index af449cf78522..ed1559034c3a 100644 --- a/x-pack/plugins/canvas/server/routes/functions/functions.ts +++ b/x-pack/plugins/canvas/server/routes/functions/functions.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { LegacyAPICaller } from 'src/core/server'; import { serializeProvider } from '../../../../../../src/plugins/expressions/common'; import { RouteInitializerDeps } from '../'; import { API_ROUTE_FUNCTIONS } from '../../../common/lib/constants'; @@ -34,12 +33,9 @@ export function initializeGetFunctionsRoute(deps: RouteInitializerDeps) { } export function initializeBatchFunctionsRoute(deps: RouteInitializerDeps) { - const { bfetch, elasticsearch, expressions } = deps; + const { bfetch, expressions } = deps; - async function runFunction( - handlers: { environment: string; elasticsearchClient: LegacyAPICaller }, - fnCall: FunctionCall - ) { + async function runFunction(handlers: { environment: string }, fnCall: FunctionCall) { const { functionName, args, context } = fnCall; const { deserialize } = serializeProvider(expressions.getTypes()); @@ -61,7 +57,6 @@ export function initializeBatchFunctionsRoute(deps: RouteInitializerDeps) { onBatchItem: async (fnCall: FunctionCall) => { const handlers = { environment: 'server', - elasticsearchClient: elasticsearch.legacy.client.asScoped(request).callAsCurrentUser, }; const result = await runFunction(handlers, fnCall); if (typeof result === 'undefined') { diff --git a/x-pack/plugins/canvas/server/routes/index.ts b/x-pack/plugins/canvas/server/routes/index.ts index e42b47618ed6..ccc8f7e27826 100644 --- a/x-pack/plugins/canvas/server/routes/index.ts +++ b/x-pack/plugins/canvas/server/routes/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter, Logger, ElasticsearchServiceSetup } from 'src/core/server'; +import { IRouter, Logger } from 'src/core/server'; import { ExpressionsServerSetup } from 'src/plugins/expressions/server'; import { BfetchServerSetup } from 'src/plugins/bfetch/server'; import { initCustomElementsRoutes } from './custom_elements'; @@ -20,7 +20,6 @@ export interface RouteInitializerDeps { logger: Logger; expressions: ExpressionsServerSetup; bfetch: BfetchServerSetup; - elasticsearch: ElasticsearchServiceSetup; } export function initRoutes(deps: RouteInitializerDeps) {