diff --git a/x-pack/legacy/plugins/cross_cluster_replication/index.js b/x-pack/legacy/plugins/cross_cluster_replication/index.js index 22e8e73963cc..1b5f42fc5107 100644 --- a/x-pack/legacy/plugins/cross_cluster_replication/index.js +++ b/x-pack/legacy/plugins/cross_cluster_replication/index.js @@ -9,7 +9,7 @@ import { PLUGIN } from './common/constants'; import { registerLicenseChecker } from './server/lib/register_license_checker'; import { registerRoutes } from './server/routes/register_routes'; import { ccrDataEnricher } from './cross_cluster_replication_data'; -import { addIndexManagementDataEnricher } from '../index_management/server/index_management_data'; + export function crossClusterReplication(kibana) { return new kibana.Plugin({ id: PLUGIN.ID, @@ -49,8 +49,13 @@ export function crossClusterReplication(kibana) { init: function initCcrPlugin(server) { registerLicenseChecker(server); registerRoutes(server); - if (server.config().get('xpack.ccr.ui.enabled')) { - addIndexManagementDataEnricher(ccrDataEnricher); + + if ( + server.config().get('xpack.ccr.ui.enabled') && + server.plugins.index_management && + server.plugins.index_management.addIndexManagementDataEnricher + ) { + server.plugins.index_management.addIndexManagementDataEnricher(ccrDataEnricher); } }, }); diff --git a/x-pack/legacy/plugins/index_management/common/constants/plugin.ts b/x-pack/legacy/plugins/index_management/common/constants/plugin.ts index 1f283464df9a..2cd137f62d3d 100644 --- a/x-pack/legacy/plugins/index_management/common/constants/plugin.ts +++ b/x-pack/legacy/plugins/index_management/common/constants/plugin.ts @@ -4,13 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { LICENSE_TYPE_BASIC } from '../../../../common/constants'; +import { LicenseType } from '../../../../../plugins/licensing/common/types'; + +const basicLicense: LicenseType = 'basic'; export const PLUGIN = { - ID: 'index_management', + id: 'index_management', + minimumLicenseType: basicLicense, getI18nName: (i18n: any): string => i18n.translate('xpack.idxMgmt.appTitle', { defaultMessage: 'Index Management', }), - MINIMUM_LICENSE_REQUIRED: LICENSE_TYPE_BASIC, }; diff --git a/x-pack/legacy/plugins/index_management/common/index.ts b/x-pack/legacy/plugins/index_management/common/index.ts new file mode 100644 index 000000000000..0cc4ba79711c --- /dev/null +++ b/x-pack/legacy/plugins/index_management/common/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { PLUGIN, API_BASE_PATH } from './constants'; diff --git a/x-pack/legacy/plugins/index_management/index.ts b/x-pack/legacy/plugins/index_management/index.ts index f2a543337199..c92b38c0d94b 100644 --- a/x-pack/legacy/plugins/index_management/index.ts +++ b/x-pack/legacy/plugins/index_management/index.ts @@ -5,19 +5,15 @@ */ import { resolve } from 'path'; -import { i18n } from '@kbn/i18n'; import { Legacy } from 'kibana'; -import { createRouter } from '../../server/lib/create_router'; -import { registerLicenseChecker } from '../../server/lib/register_license_checker'; -import { PLUGIN, API_BASE_PATH } from './common/constants'; -import { LegacySetup } from './server/plugin'; -import { plugin as initServerPlugin } from './server'; +import { PLUGIN } from './common/constants'; +import { plugin as initServerPlugin, Dependencies } from './server'; export type ServerFacade = Legacy.Server; export function indexManagement(kibana: any) { return new kibana.Plugin({ - id: PLUGIN.ID, + id: PLUGIN.id, configPrefix: 'xpack.index_management', publicDir: resolve(__dirname, 'public'), require: ['kibana', 'elasticsearch', 'xpack_main'], @@ -29,32 +25,15 @@ export function indexManagement(kibana: any) { init(server: ServerFacade) { const coreSetup = server.newPlatform.setup.core; - - const pluginsSetup = {}; - - const __LEGACY: LegacySetup = { - router: createRouter(server, PLUGIN.ID, `${API_BASE_PATH}/`), - plugins: { - license: { - registerLicenseChecker: registerLicenseChecker.bind( - null, - server, - PLUGIN.ID, - PLUGIN.getI18nName(i18n), - PLUGIN.MINIMUM_LICENSE_REQUIRED as 'basic' - ), - }, - elasticsearch: server.plugins.elasticsearch, - }, + const coreInitializerContext = server.newPlatform.coreContext; + const pluginsSetup: Dependencies = { + licensing: server.newPlatform.setup.plugins.licensing as any, }; - const serverPlugin = initServerPlugin(); - const indexMgmtSetup = serverPlugin.setup(coreSetup, pluginsSetup, __LEGACY); + const serverPlugin = initServerPlugin(coreInitializerContext as any); + const serverPublicApi = serverPlugin.setup(coreSetup, pluginsSetup); - server.expose( - 'addIndexManagementDataEnricher', - indexMgmtSetup.addIndexManagementDataEnricher - ); + server.expose('addIndexManagementDataEnricher', serverPublicApi.indexDataEnricher.add); }, }); } diff --git a/x-pack/legacy/plugins/index_management/server/index.ts b/x-pack/legacy/plugins/index_management/server/index.ts index c405f7816337..866b374740d3 100644 --- a/x-pack/legacy/plugins/index_management/server/index.ts +++ b/x-pack/legacy/plugins/index_management/server/index.ts @@ -3,8 +3,10 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { IndexMgmtPlugin } from './plugin'; -export function plugin() { - return new IndexMgmtPlugin(); -} +import { PluginInitializerContext } from 'src/core/server'; +import { IndexMgmtServerPlugin } from './plugin'; + +export const plugin = (ctx: PluginInitializerContext) => new IndexMgmtServerPlugin(ctx); + +export { Dependencies } from './types'; diff --git a/x-pack/legacy/plugins/index_management/server/index_management_data.ts b/x-pack/legacy/plugins/index_management/server/index_management_data.ts deleted file mode 100644 index e730761979e1..000000000000 --- a/x-pack/legacy/plugins/index_management/server/index_management_data.ts +++ /dev/null @@ -1,15 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -const indexManagementDataEnrichers: any[] = []; - -export const addIndexManagementDataEnricher = (enricher: any) => { - indexManagementDataEnrichers.push(enricher); -}; - -export const getIndexManagementDataEnrichers = () => { - return indexManagementDataEnrichers; -}; diff --git a/x-pack/legacy/plugins/index_management/server/lib/fetch_indices.ts b/x-pack/legacy/plugins/index_management/server/lib/fetch_indices.ts index 19a5cd81c919..d9f01ee06014 100644 --- a/x-pack/legacy/plugins/index_management/server/lib/fetch_indices.ts +++ b/x-pack/legacy/plugins/index_management/server/lib/fetch_indices.ts @@ -3,8 +3,10 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { IndexDataEnricher } from '../services'; +import { Index, CallAsCurrentUser } from '../types'; import { fetchAliases } from './fetch_aliases'; -import { getIndexManagementDataEnrichers } from '../index_management_data'; + interface Hit { health: string; status: string; @@ -27,22 +29,7 @@ interface Params { index?: string[]; } -const enrichResponse = async (response: any, callWithRequest: any) => { - let enrichedResponse = response; - const dataEnrichers = getIndexManagementDataEnrichers(); - for (let i = 0; i < dataEnrichers.length; i++) { - const dataEnricher = dataEnrichers[i]; - try { - const dataEnricherResponse = await dataEnricher(enrichedResponse, callWithRequest); - enrichedResponse = dataEnricherResponse; - } catch (e) { - // silently swallow enricher response errors - } - } - return enrichedResponse; -}; - -function formatHits(hits: Hit[], aliases: Aliases) { +function formatHits(hits: Hit[], aliases: Aliases): Index[] { return hits.map((hit: Hit) => { return { health: hit.health, @@ -59,7 +46,7 @@ function formatHits(hits: Hit[], aliases: Aliases) { }); } -async function fetchIndicesCall(callWithRequest: any, indexNames?: string[]) { +async function fetchIndicesCall(callAsCurrentUser: CallAsCurrentUser, indexNames?: string[]) { const params: Params = { format: 'json', h: 'health,status,index,uuid,pri,rep,docs.count,sth,store.size', @@ -69,13 +56,17 @@ async function fetchIndicesCall(callWithRequest: any, indexNames?: string[]) { params.index = indexNames; } - return await callWithRequest('cat.indices', params); + return await callAsCurrentUser('cat.indices', params); } -export const fetchIndices = async (callWithRequest: any, indexNames?: string[]) => { - const aliases = await fetchAliases(callWithRequest); - const hits = await fetchIndicesCall(callWithRequest, indexNames); - let response = formatHits(hits, aliases); - response = await enrichResponse(response, callWithRequest); - return response; +export const fetchIndices = async ( + callAsCurrentUser: CallAsCurrentUser, + indexDataEnricher: IndexDataEnricher, + indexNames?: string[] +) => { + const aliases = await fetchAliases(callAsCurrentUser); + const hits = await fetchIndicesCall(callAsCurrentUser, indexNames); + const indices = formatHits(hits, aliases); + + return await indexDataEnricher.enrichIndices(indices, callAsCurrentUser); }; diff --git a/x-pack/legacy/plugins/index_management/server/lib/get_managed_templates.ts b/x-pack/legacy/plugins/index_management/server/lib/get_managed_templates.ts index ebffe73eb23a..2fdb21ea4b0d 100644 --- a/x-pack/legacy/plugins/index_management/server/lib/get_managed_templates.ts +++ b/x-pack/legacy/plugins/index_management/server/lib/get_managed_templates.ts @@ -7,10 +7,10 @@ // Cloud has its own system for managing templates and we want to make // this clear in the UI when a template is used in a Cloud deployment. export const getManagedTemplatePrefix = async ( - callWithInternalUser: any + callAsCurrentUser: any ): Promise => { try { - const { persistent, transient, defaults } = await callWithInternalUser('cluster.getSettings', { + const { persistent, transient, defaults } = await callAsCurrentUser('cluster.getSettings', { filterPath: '*.*managed_index_templates', flatSettings: true, includeDefaults: true, diff --git a/x-pack/legacy/plugins/index_management/server/lib/is_es_error.ts b/x-pack/legacy/plugins/index_management/server/lib/is_es_error.ts new file mode 100644 index 000000000000..4137293cf39c --- /dev/null +++ b/x-pack/legacy/plugins/index_management/server/lib/is_es_error.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as legacyElasticsearch from 'elasticsearch'; + +const esErrorsParent = legacyElasticsearch.errors._Abstract; + +export function isEsError(err: Error) { + return err instanceof esErrorsParent; +} diff --git a/x-pack/legacy/plugins/index_management/server/plugin.ts b/x-pack/legacy/plugins/index_management/server/plugin.ts index cbe19adcd58b..95d27e1cf16b 100644 --- a/x-pack/legacy/plugins/index_management/server/plugin.ts +++ b/x-pack/legacy/plugins/index_management/server/plugin.ts @@ -3,48 +3,67 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { CoreSetup } from 'src/core/server'; -import { ElasticsearchPlugin } from 'src/legacy/core_plugins/elasticsearch'; -import { Router } from '../../../server/lib/create_router'; -import { addIndexManagementDataEnricher } from './index_management_data'; -import { registerIndicesRoutes } from './routes/api/indices'; -import { registerTemplateRoutes } from './routes/api/templates'; -import { registerMappingRoute } from './routes/api/mapping'; -import { registerSettingsRoutes } from './routes/api/settings'; -import { registerStatsRoute } from './routes/api/stats'; +import { i18n } from '@kbn/i18n'; +import { CoreSetup, Plugin, Logger, PluginInitializerContext } from 'src/core/server'; -export interface LegacySetup { - router: Router; - plugins: { - elasticsearch: ElasticsearchPlugin; - license: { - registerLicenseChecker: () => void; - }; +import { PLUGIN } from '../common'; +import { Dependencies } from './types'; +import { ApiRoutes } from './routes'; +import { License, IndexDataEnricher } from './services'; +import { isEsError } from './lib/is_es_error'; + +export interface IndexMgmtSetup { + indexDataEnricher: { + add: IndexDataEnricher['add']; }; } -export interface IndexMgmtSetup { - addIndexManagementDataEnricher: (enricher: any) => void; -} +export class IndexMgmtServerPlugin implements Plugin { + private readonly apiRoutes: ApiRoutes; + private readonly license: License; + private readonly logger: Logger; + private readonly indexDataEnricher: IndexDataEnricher; -export class IndexMgmtPlugin { - public setup(core: CoreSetup, plugins: {}, __LEGACY: LegacySetup): IndexMgmtSetup { - const serverFacade = { - plugins: { - elasticsearch: __LEGACY.plugins.elasticsearch, + constructor({ logger }: PluginInitializerContext) { + this.logger = logger.get(); + this.apiRoutes = new ApiRoutes(); + this.license = new License(); + this.indexDataEnricher = new IndexDataEnricher(); + } + + setup({ http }: CoreSetup, { licensing }: Dependencies): IndexMgmtSetup { + const router = http.createRouter(); + + this.license.setup( + { + pluginId: PLUGIN.id, + minimumLicenseType: PLUGIN.minimumLicenseType, + defaultErrorMessage: i18n.translate('xpack.idxMgmt.licenseCheckErrorMessage', { + defaultMessage: 'License check failed', + }), }, - }; + { + licensing, + logger: this.logger, + } + ); - __LEGACY.plugins.license.registerLicenseChecker(); - - registerIndicesRoutes(__LEGACY.router); - registerTemplateRoutes(__LEGACY.router, serverFacade); - registerSettingsRoutes(__LEGACY.router); - registerStatsRoute(__LEGACY.router); - registerMappingRoute(__LEGACY.router); + this.apiRoutes.setup({ + router, + license: this.license, + indexDataEnricher: this.indexDataEnricher, + lib: { + isEsError, + }, + }); return { - addIndexManagementDataEnricher, + indexDataEnricher: { + add: this.indexDataEnricher.add.bind(this.indexDataEnricher), + }, }; } + + start() {} + stop() {} } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/index.ts b/x-pack/legacy/plugins/index_management/server/routes/api/index.ts new file mode 100644 index 000000000000..4ed008480c14 --- /dev/null +++ b/x-pack/legacy/plugins/index_management/server/routes/api/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { API_BASE_PATH } from '../../../common'; + +export const addBasePath = (uri: string): string => API_BASE_PATH + uri; diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts index 8bd370a3eb3b..ec42b2aee45a 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts @@ -3,26 +3,41 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; -interface ReqPayload { - indices: string[]; -} - -const handler: RouterRouteHandler = async (request, callWithRequest, h) => { - const payload = request.payload as ReqPayload; - const { indices = [] } = payload; - - const params = { - expandWildcards: 'none', - format: 'json', - index: indices, - }; - - await callWithRequest('indices.clearCache', params); - return h.response(); -}; - -export function registerClearCacheRoute(router: Router) { - router.post('indices/clear_cache', handler); +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; + +const bodySchema = schema.object({ + indices: schema.arrayOf(schema.string()), +}); + +export function registerClearCacheRoute({ router, license, lib }: RouteDependencies) { + router.post( + { path: addBasePath('/indices/clear_cache'), validate: { body: bodySchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const payload = req.body as typeof bodySchema.type; + const { indices = [] } = payload; + + const params = { + expandWildcards: 'none', + format: 'json', + index: indices, + }; + + try { + await ctx.core.elasticsearch.dataClient.callAsCurrentUser('indices.clearCache', params); + return res.ok(); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_close_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_close_route.ts index 6e304f1762ac..bd243ab3e5de 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_close_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_close_route.ts @@ -3,26 +3,41 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; -interface ReqPayload { - indices: string[]; -} - -const handler: RouterRouteHandler = async (request, callWithRequest, h) => { - const payload = request.payload as ReqPayload; - const { indices = [] } = payload; - - const params = { - expandWildcards: 'none', - format: 'json', - index: indices, - }; - - await callWithRequest('indices.close', params); - return h.response(); -}; - -export function registerCloseRoute(router: Router) { - router.post('indices/close', handler); +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; + +const bodySchema = schema.object({ + indices: schema.arrayOf(schema.string()), +}); + +export function registerCloseRoute({ router, license, lib }: RouteDependencies) { + router.post( + { path: addBasePath('/indices/close'), validate: { body: bodySchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const payload = req.body as typeof bodySchema.type; + const { indices = [] } = payload; + + const params = { + expandWildcards: 'none', + format: 'json', + index: indices, + }; + + try { + await ctx.core.elasticsearch.dataClient.callAsCurrentUser('indices.close', params); + return res.ok(); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_delete_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_delete_route.ts index 0d2268eca179..ffe30b315363 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_delete_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_delete_route.ts @@ -4,25 +4,41 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; -interface ReqPayload { - indices: string[]; -} - -const handler: RouterRouteHandler = async (request, callWithRequest, h) => { - const payload = request.payload as ReqPayload; - const { indices = [] } = payload; - - const params = { - expandWildcards: 'none', - format: 'json', - index: indices, - }; - await callWithRequest('indices.delete', params); - return h.response(); -}; - -export function registerDeleteRoute(router: Router) { - router.post('indices/delete', handler); +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; + +const bodySchema = schema.object({ + indices: schema.arrayOf(schema.string()), +}); + +export function registerDeleteRoute({ router, license, lib }: RouteDependencies) { + router.post( + { path: addBasePath('/indices/delete'), validate: { body: bodySchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const body = req.body as typeof bodySchema.type; + const { indices = [] } = body; + + const params = { + expandWildcards: 'none', + format: 'json', + index: indices, + }; + + try { + await ctx.core.elasticsearch.dataClient.callAsCurrentUser('indices.delete', params); + return res.ok(); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_flush_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_flush_route.ts index 0623d8030571..fee3a0f5278d 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_flush_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_flush_route.ts @@ -4,26 +4,41 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; -interface ReqPayload { - indices: string[]; -} - -const handler: RouterRouteHandler = async (request, callWithRequest, h) => { - const payload = request.payload as ReqPayload; - const { indices = [] } = payload; - - const params = { - expandWildcards: 'none', - format: 'json', - index: indices, - }; - - await callWithRequest('indices.flush', params); - return h.response(); -}; - -export function registerFlushRoute(router: Router) { - router.post('indices/flush', handler); +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; + +const bodySchema = schema.object({ + indices: schema.arrayOf(schema.string()), +}); + +export function registerFlushRoute({ router, license, lib }: RouteDependencies) { + router.post( + { path: addBasePath('/indices/flush'), validate: { body: bodySchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const body = req.body as typeof bodySchema.type; + const { indices = [] } = body; + + const params = { + expandWildcards: 'none', + format: 'json', + index: indices, + }; + + try { + await ctx.core.elasticsearch.dataClient.callAsCurrentUser('indices.flush', params); + return res.ok(); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_forcemerge_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_forcemerge_route.ts index c0a0ae48c34b..c39547a3cbd4 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_forcemerge_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_forcemerge_route.ts @@ -4,34 +4,48 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; -interface ForceMergeReqPayload { - maxNumSegments: number; - indices: string[]; -} - -interface Params { - expandWildcards: string; - index: ForceMergeReqPayload['indices']; - max_num_segments?: ForceMergeReqPayload['maxNumSegments']; -} - -const handler: RouterRouteHandler = async (request, callWithRequest, h) => { - const { maxNumSegments, indices = [] } = request.payload as ForceMergeReqPayload; - const params: Params = { - expandWildcards: 'none', - index: indices, - }; - - if (maxNumSegments) { - params.max_num_segments = maxNumSegments; - } - - await callWithRequest('indices.forcemerge', params); - return h.response(); -}; - -export function registerForcemergeRoute(router: Router) { - router.post('indices/forcemerge', handler); +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; + +const bodySchema = schema.object({ + indices: schema.arrayOf(schema.string()), + maxNumSegments: schema.maybe(schema.number()), +}); + +export function registerForcemergeRoute({ router, license, lib }: RouteDependencies) { + router.post( + { + path: addBasePath('/indices/forcemerge'), + validate: { + body: bodySchema, + }, + }, + license.guardApiRoute(async (ctx, req, res) => { + const { maxNumSegments, indices = [] } = req.body as typeof bodySchema.type; + const params = { + expandWildcards: 'none', + index: indices, + }; + + if (maxNumSegments) { + (params as any).max_num_segments = maxNumSegments; + } + + try { + await ctx.core.elasticsearch.dataClient.callAsCurrentUser('indices.forcemerge', params); + return res.ok(); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_freeze_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_freeze_route.ts index 658a904f08fe..68bb4b13ef47 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_freeze_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_freeze_route.ts @@ -4,25 +4,43 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; -interface ReqPayload { - indices: string[]; -} - -const handler: RouterRouteHandler = async (request, callWithRequest, h) => { - const payload = request.payload as ReqPayload; - const { indices = [] } = payload; - - const params = { - path: `/${encodeURIComponent(indices.join(','))}/_freeze`, - method: 'POST', - }; - - await callWithRequest('transport.request', params); - return h.response(); -}; - -export function registerFreezeRoute(router: Router) { - router.post('indices/freeze', handler); +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; + +const bodySchema = schema.object({ + indices: schema.arrayOf(schema.string()), +}); + +export function registerFreezeRoute({ router, license, lib }: RouteDependencies) { + router.post( + { path: addBasePath('/indices/freeze'), validate: { body: bodySchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const body = req.body as typeof bodySchema.type; + const { indices = [] } = body; + + const params = { + path: `/${encodeURIComponent(indices.join(','))}/_freeze`, + method: 'POST', + }; + + try { + await await ctx.core.elasticsearch.dataClient.callAsCurrentUser( + 'transport.request', + params + ); + return res.ok(); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_indices_routes.ts b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_indices_routes.ts index 977ef689f44b..e1165b5d689a 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_indices_routes.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_indices_routes.ts @@ -3,7 +3,7 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Router } from '../../../../../../server/lib/create_router'; +import { RouteDependencies } from '../../../types'; import { registerClearCacheRoute } from './register_clear_cache_route'; import { registerCloseRoute } from './register_close_route'; @@ -17,16 +17,16 @@ import { registerDeleteRoute } from './register_delete_route'; import { registerFreezeRoute } from './register_freeze_route'; import { registerUnfreezeRoute } from './register_unfreeze_route'; -export function registerIndicesRoutes(router: Router) { - registerClearCacheRoute(router); - registerCloseRoute(router); - registerFlushRoute(router); - registerForcemergeRoute(router); - registerListRoute(router); - registerOpenRoute(router); - registerRefreshRoute(router); - registerReloadRoute(router); - registerDeleteRoute(router); - registerFreezeRoute(router); - registerUnfreezeRoute(router); +export function registerIndicesRoutes(dependencies: RouteDependencies) { + registerClearCacheRoute(dependencies); + registerCloseRoute(dependencies); + registerFlushRoute(dependencies); + registerForcemergeRoute(dependencies); + registerListRoute(dependencies); + registerOpenRoute(dependencies); + registerRefreshRoute(dependencies); + registerReloadRoute(dependencies); + registerDeleteRoute(dependencies); + registerFreezeRoute(dependencies); + registerUnfreezeRoute(dependencies); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_list_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_list_route.ts index d8b8018a975c..1f5d8ddf529e 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_list_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_list_route.ts @@ -3,14 +3,31 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; import { fetchIndices } from '../../../lib/fetch_indices'; +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; -const handler: RouterRouteHandler = async (request, callWithRequest) => { - return fetchIndices(callWithRequest); -}; - -export function registerListRoute(router: Router) { - router.get('indices', handler); +export function registerListRoute({ router, license, indexDataEnricher, lib }: RouteDependencies) { + router.get( + { path: addBasePath('/indices'), validate: false }, + license.guardApiRoute(async (ctx, req, res) => { + try { + const indices = await fetchIndices( + ctx.core.elasticsearch.dataClient.callAsCurrentUser, + indexDataEnricher + ); + return res.ok({ body: indices }); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_open_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_open_route.ts index 50c2540ec004..28dbae0d8864 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_open_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_open_route.ts @@ -3,25 +3,41 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; -interface ReqPayload { - indices: string[]; -} - -const handler: RouterRouteHandler = async (request, callWithRequest, h) => { - const payload = request.payload as ReqPayload; - const { indices = [] } = payload; - - const params = { - expandWildcards: 'none', - format: 'json', - index: indices, - }; - await callWithRequest('indices.open', params); - return h.response(); -}; - -export function registerOpenRoute(router: Router) { - router.post('indices/open', handler); +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; + +const bodySchema = schema.object({ + indices: schema.arrayOf(schema.string()), +}); + +export function registerOpenRoute({ router, license, lib }: RouteDependencies) { + router.post( + { path: addBasePath('/indices/open'), validate: { body: bodySchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const body = req.body as typeof bodySchema.type; + const { indices = [] } = body; + + const params = { + expandWildcards: 'none', + format: 'json', + index: indices, + }; + + try { + await await ctx.core.elasticsearch.dataClient.callAsCurrentUser('indices.open', params); + return res.ok(); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_refresh_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_refresh_route.ts index 093075652821..34fee477662e 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_refresh_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_refresh_route.ts @@ -4,25 +4,41 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; -interface ReqPayload { - indices: string[]; -} - -const handler: RouterRouteHandler = async (request, callWithRequest, h) => { - const payload = request.payload as ReqPayload; - const { indices = [] } = payload; - - const params = { - expandWildcards: 'none', - format: 'json', - index: indices, - }; - await callWithRequest('indices.refresh', params); - return h.response(); -}; - -export function registerRefreshRoute(router: Router) { - router.post('indices/refresh', handler); +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; + +const bodySchema = schema.object({ + indices: schema.arrayOf(schema.string()), +}); + +export function registerRefreshRoute({ router, license, lib }: RouteDependencies) { + router.post( + { path: addBasePath('/indices/refresh'), validate: { body: bodySchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const body = req.body as typeof bodySchema.type; + const { indices = [] } = body; + + const params = { + expandWildcards: 'none', + format: 'json', + index: indices, + }; + + try { + await ctx.core.elasticsearch.dataClient.callAsCurrentUser('indices.refresh', params); + return res.ok(); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_reload_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_reload_route.ts index 7371cc1c2d9f..22a9d79439ab 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_reload_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_reload_route.ts @@ -3,19 +3,46 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; +import { RouteDependencies } from '../../../types'; import { fetchIndices } from '../../../lib/fetch_indices'; +import { addBasePath } from '../index'; -interface ReqPayload { - indexNames: string[]; -} - -const handler: RouterRouteHandler = async (request, callWithRequest) => { - const { indexNames = [] } = request.payload as ReqPayload; - return fetchIndices(callWithRequest, indexNames); -}; - -export function registerReloadRoute(router: Router) { - router.post('indices/reload', handler); +const bodySchema = schema.maybe( + schema.object({ + indexNames: schema.maybe(schema.arrayOf(schema.string())), + }) +); + +export function registerReloadRoute({ + router, + license, + indexDataEnricher, + lib, +}: RouteDependencies) { + router.post( + { path: addBasePath('/indices/reload'), validate: { body: bodySchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const { indexNames = [] } = (req.body as typeof bodySchema.type) ?? {}; + + try { + const indices = await fetchIndices( + ctx.core.elasticsearch.dataClient.callAsCurrentUser, + indexDataEnricher, + indexNames + ); + return res.ok({ body: indices }); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_unfreeze_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_unfreeze_route.ts index 0db882c5171e..67c4a3516d1e 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_unfreeze_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/indices/register_unfreeze_route.ts @@ -4,23 +4,38 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; -interface ReqPayload { - indices: string[]; -} - -const handler: RouterRouteHandler = async (request, callWithRequest, h) => { - const { indices = [] } = request.payload as ReqPayload; - const params = { - path: `/${encodeURIComponent(indices.join(','))}/_unfreeze`, - method: 'POST', - }; - - await callWithRequest('transport.request', params); - return h.response(); -}; - -export function registerUnfreezeRoute(router: Router) { - router.post('indices/unfreeze', handler); +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; + +const bodySchema = schema.object({ + indices: schema.arrayOf(schema.string()), +}); + +export function registerUnfreezeRoute({ router, license, lib }: RouteDependencies) { + router.post( + { path: addBasePath('/indices/unfreeze'), validate: { body: bodySchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const { indices = [] } = req.body as typeof bodySchema.type; + const params = { + path: `/${encodeURIComponent(indices.join(','))}/_unfreeze`, + method: 'POST', + }; + + try { + await ctx.core.elasticsearch.dataClient.callAsCurrentUser('transport.request', params); + return res.ok(); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/mapping/register_mapping_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/mapping/register_mapping_route.ts index 86600aab7658..20d7e6b4d723 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/mapping/register_mapping_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/mapping/register_mapping_route.ts @@ -3,7 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; + +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; + +const paramsSchema = schema.object({ + indexName: schema.string(), +}); function formatHit(hit: { [key: string]: { mappings: any } }, indexName: string) { const mapping = hit[indexName].mappings; @@ -12,18 +19,33 @@ function formatHit(hit: { [key: string]: { mappings: any } }, indexName: string) }; } -const handler: RouterRouteHandler = async (request, callWithRequest) => { - const { indexName } = request.params; - const params = { - expand_wildcards: 'none', - index: indexName, - }; +export function registerMappingRoute({ router, license, lib }: RouteDependencies) { + router.get( + { path: addBasePath('/mapping/{indexName}'), validate: { params: paramsSchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const { indexName } = req.params as typeof paramsSchema.type; + const params = { + expand_wildcards: 'none', + index: indexName, + }; - const hit = await callWithRequest('indices.getMapping', params); - const response = formatHit(hit, indexName); - return response; -}; - -export function registerMappingRoute(router: Router) { - router.get('mapping/{indexName}', handler); + try { + const hit = await ctx.core.elasticsearch.dataClient.callAsCurrentUser( + 'indices.getMapping', + params + ); + const response = formatHit(hit, indexName); + return res.ok({ body: response }); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/settings/register_load_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/settings/register_load_route.ts index 70b96c3912e7..c31813b4a9f4 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/settings/register_load_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/settings/register_load_route.ts @@ -3,7 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; + +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; + +const paramsSchema = schema.object({ + indexName: schema.string(), +}); // response comes back as { [indexName]: { ... }} // so plucking out the embedded object @@ -12,19 +19,35 @@ function formatHit(hit: { [key: string]: {} }) { return hit[key]; } -const handler: RouterRouteHandler = async (request, callWithRequest) => { - const { indexName } = request.params; - const params = { - expandWildcards: 'none', - flatSettings: false, - local: false, - includeDefaults: true, - index: indexName, - }; +export function registerLoadRoute({ router, license, lib }: RouteDependencies) { + router.get( + { path: addBasePath('/settings/{indexName}'), validate: { params: paramsSchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const { indexName } = req.params as typeof paramsSchema.type; + const params = { + expandWildcards: 'none', + flatSettings: false, + local: false, + includeDefaults: true, + index: indexName, + }; - const hit = await callWithRequest('indices.getSettings', params); - return formatHit(hit); -}; -export function registerLoadRoute(router: Router) { - router.get('settings/{indexName}', handler); + try { + const hit = await ctx.core.elasticsearch.dataClient.callAsCurrentUser( + 'indices.getSettings', + params + ); + return res.ok({ body: formatHit(hit) }); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/settings/register_settings_routes.ts b/x-pack/legacy/plugins/index_management/server/routes/api/settings/register_settings_routes.ts index 2fe1786f266b..501566f8b62d 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/settings/register_settings_routes.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/settings/register_settings_routes.ts @@ -3,12 +3,12 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Router } from '../../../../../../server/lib/create_router'; +import { RouteDependencies } from '../../../types'; import { registerLoadRoute } from './register_load_route'; import { registerUpdateRoute } from './register_update_route'; -export function registerSettingsRoutes(router: Router) { - registerLoadRoute(router); - registerUpdateRoute(router); +export function registerSettingsRoutes(dependencies: RouteDependencies) { + registerLoadRoute(dependencies); + registerUpdateRoute(dependencies); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/settings/register_update_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/settings/register_update_route.ts index 4d28b5b4ac3b..9ce5ae7f9939 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/settings/register_update_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/settings/register_update_route.ts @@ -3,20 +3,49 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; -const handler: RouterRouteHandler = async (request, callWithRequest) => { - const { indexName } = request.params; - const params = { - ignoreUnavailable: true, - allowNoIndices: false, - expandWildcards: 'none', - index: indexName, - body: request.payload, - }; +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; - return await callWithRequest('indices.putSettings', params); -}; -export function registerUpdateRoute(router: Router) { - router.put('settings/{indexName}', handler); +const bodySchema = schema.any(); + +const paramsSchema = schema.object({ + indexName: schema.string(), +}); + +export function registerUpdateRoute({ router, license, lib }: RouteDependencies) { + router.put( + { + path: addBasePath('/settings/{indexName}'), + validate: { body: bodySchema, params: paramsSchema }, + }, + license.guardApiRoute(async (ctx, req, res) => { + const { indexName } = req.params as typeof paramsSchema.type; + const params = { + ignoreUnavailable: true, + allowNoIndices: false, + expandWildcards: 'none', + index: indexName, + body: req.body, + }; + + try { + const response = await ctx.core.elasticsearch.dataClient.callAsCurrentUser( + 'indices.putSettings', + params + ); + return res.ok({ body: response }); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/stats/register_stats_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/stats/register_stats_route.ts index 33d0df53e079..f408fd6584bd 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/stats/register_stats_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/stats/register_stats_route.ts @@ -3,7 +3,14 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; + +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; + +const paramsSchema = schema.object({ + indexName: schema.string(), +}); function formatHit(hit: { _shards: any; indices: { [key: string]: any } }, indexName: string) { const { _shards, indices } = hit; @@ -14,17 +21,32 @@ function formatHit(hit: { _shards: any; indices: { [key: string]: any } }, index }; } -const handler: RouterRouteHandler = async (request, callWithRequest) => { - const { indexName } = request.params; - const params = { - expand_wildcards: 'none', - index: indexName, - }; - const hit = await callWithRequest('indices.stats', params); - const response = formatHit(hit, indexName); +export function registerStatsRoute({ router, license, lib }: RouteDependencies) { + router.get( + { path: addBasePath('/stats/{indexName}'), validate: { params: paramsSchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const { indexName } = req.params as typeof paramsSchema.type; + const params = { + expand_wildcards: 'none', + index: indexName, + }; - return response; -}; -export function registerStatsRoute(router: Router) { - router.get('stats/{indexName}', handler); + try { + const hit = await ctx.core.elasticsearch.dataClient.callAsCurrentUser( + 'indices.stats', + params + ); + return res.ok({ body: formatHit(hit, indexName) }); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_create_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_create_route.ts index e134a97dd029..817893976767 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_create_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_create_route.ts @@ -5,60 +5,74 @@ */ import { i18n } from '@kbn/i18n'; -import { - Router, - RouterRouteHandler, - wrapCustomError, -} from '../../../../../../server/lib/create_router'; + import { Template, TemplateEs } from '../../../../common/types'; import { serializeTemplate } from '../../../../common/lib'; +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; +import { templateSchema } from './validate_schemas'; -const handler: RouterRouteHandler = async (req, callWithRequest) => { - const template = req.payload as Template; - const serializedTemplate = serializeTemplate(template) as TemplateEs; +const bodySchema = templateSchema; - const { name, order, index_patterns, version, settings, mappings, aliases } = serializedTemplate; +export function registerCreateRoute({ router, license, lib }: RouteDependencies) { + router.put( + { path: addBasePath('/templates'), validate: { body: bodySchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const { callAsCurrentUser } = ctx.core.elasticsearch.dataClient; + const template = req.body as Template; + const serializedTemplate = serializeTemplate(template) as TemplateEs; - const conflictError = wrapCustomError( - new Error( - i18n.translate('xpack.idxMgmt.createRoute.duplicateTemplateIdErrorMessage', { - defaultMessage: "There is already a template with name '{name}'.", - values: { + const { + name, + order, + index_patterns, + version, + settings, + mappings, + aliases, + } = serializedTemplate; + + // Check that template with the same name doesn't already exist + const templateExists = await callAsCurrentUser('indices.existsTemplate', { name }); + + if (templateExists) { + return res.conflict({ + body: new Error( + i18n.translate('xpack.idxMgmt.createRoute.duplicateTemplateIdErrorMessage', { + defaultMessage: "There is already a template with name '{name}'.", + values: { + name, + }, + }) + ), + }); + } + + try { + // Otherwise create new index template + const response = await callAsCurrentUser('indices.putTemplate', { name, - }, - }) - ), - 409 + order, + body: { + index_patterns, + version, + settings, + mappings, + aliases, + }, + }); + + return res.ok({ body: response }); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) ); - - // Check that template with the same name doesn't already exist - try { - const templateExists = await callWithRequest('indices.existsTemplate', { name }); - - if (templateExists) { - throw conflictError; - } - } catch (e) { - // Rethrow conflict error but silently swallow all others - if (e === conflictError) { - throw e; - } - } - - // Otherwise create new index template - return await callWithRequest('indices.putTemplate', { - name, - order, - body: { - index_patterns, - version, - settings, - mappings, - aliases, - }, - }); -}; - -export function registerCreateRoute(router: Router) { - router.put('templates', handler); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_delete_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_delete_route.ts index b48354127b9f..c9f1995204d8 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_delete_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_delete_route.ts @@ -4,38 +4,46 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - Router, - RouterRouteHandler, - wrapEsError, -} from '../../../../../../server/lib/create_router'; +import { schema } from '@kbn/config-schema'; + +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; +import { wrapEsError } from '../../helpers'; + import { Template } from '../../../../common/types'; -const handler: RouterRouteHandler = async (req, callWithRequest) => { - const { names } = req.params; - const templateNames = names.split(','); - const response: { templatesDeleted: Array; errors: any[] } = { - templatesDeleted: [], - errors: [], - }; +const paramsSchema = schema.object({ + names: schema.string(), +}); - await Promise.all( - templateNames.map(async name => { - try { - await callWithRequest('indices.deleteTemplate', { name }); - return response.templatesDeleted.push(name); - } catch (e) { - return response.errors.push({ - name, - error: wrapEsError(e), - }); - } +export function registerDeleteRoute({ router, license }: RouteDependencies) { + router.delete( + { path: addBasePath('/templates/{names}'), validate: { params: paramsSchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const { names } = req.params as typeof paramsSchema.type; + const templateNames = names.split(','); + const response: { templatesDeleted: Array; errors: any[] } = { + templatesDeleted: [], + errors: [], + }; + + await Promise.all( + templateNames.map(async name => { + try { + await ctx.core.elasticsearch.dataClient.callAsCurrentUser('indices.deleteTemplate', { + name, + }); + return response.templatesDeleted.push(name); + } catch (e) { + return response.errors.push({ + name, + error: wrapEsError(e), + }); + } + }) + ); + + return res.ok({ body: response }); }) ); - - return response; -}; - -export function registerDeleteRoute(router: Router) { - router.delete('templates/{names}', handler); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_get_routes.ts b/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_get_routes.ts index b450f75d1cc5..d6776d774d3b 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_get_routes.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_get_routes.ts @@ -3,37 +3,62 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { schema } from '@kbn/config-schema'; import { deserializeTemplate, deserializeTemplateList } from '../../../../common/lib'; -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; import { getManagedTemplatePrefix } from '../../../lib/get_managed_templates'; +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; -let callWithInternalUser: any; +export function registerGetAllRoute({ router, license }: RouteDependencies) { + router.get( + { path: addBasePath('/templates'), validate: false }, + license.guardApiRoute(async (ctx, req, res) => { + const { callAsCurrentUser } = ctx.core.elasticsearch.dataClient; + const managedTemplatePrefix = await getManagedTemplatePrefix(callAsCurrentUser); -const allHandler: RouterRouteHandler = async (_req, callWithRequest) => { - const managedTemplatePrefix = await getManagedTemplatePrefix(callWithInternalUser); + const indexTemplatesByName = await callAsCurrentUser('indices.getTemplate'); - const indexTemplatesByName = await callWithRequest('indices.getTemplate'); - - return deserializeTemplateList(indexTemplatesByName, managedTemplatePrefix); -}; - -const oneHandler: RouterRouteHandler = async (req, callWithRequest) => { - const { name } = req.params; - const managedTemplatePrefix = await getManagedTemplatePrefix(callWithInternalUser); - const indexTemplateByName = await callWithRequest('indices.getTemplate', { name }); - - if (indexTemplateByName[name]) { - return deserializeTemplate({ ...indexTemplateByName[name], name }, managedTemplatePrefix); - } -}; - -export function registerGetAllRoute(router: Router, server: any) { - callWithInternalUser = server.plugins.elasticsearch.getCluster('data').callWithInternalUser; - router.get('templates', allHandler); + return res.ok({ body: deserializeTemplateList(indexTemplatesByName, managedTemplatePrefix) }); + }) + ); } -export function registerGetOneRoute(router: Router, server: any) { - callWithInternalUser = server.plugins.elasticsearch.getCluster('data').callWithInternalUser; - router.get('templates/{name}', oneHandler); +const paramsSchema = schema.object({ + name: schema.string(), +}); + +export function registerGetOneRoute({ router, license, lib }: RouteDependencies) { + router.get( + { path: addBasePath('/templates/{name}'), validate: { params: paramsSchema } }, + license.guardApiRoute(async (ctx, req, res) => { + const { name } = req.params as typeof paramsSchema.type; + const { callAsCurrentUser } = ctx.core.elasticsearch.dataClient; + + try { + const managedTemplatePrefix = await getManagedTemplatePrefix(callAsCurrentUser); + const indexTemplateByName = await callAsCurrentUser('indices.getTemplate', { name }); + + if (indexTemplateByName[name]) { + return res.ok({ + body: deserializeTemplate( + { ...indexTemplateByName[name], name }, + managedTemplatePrefix + ), + }); + } + + return res.notFound(); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_template_routes.ts b/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_template_routes.ts index b1dcad3f4c36..2b657346a2f8 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_template_routes.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_template_routes.ts @@ -4,16 +4,17 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Router } from '../../../../../../server/lib/create_router'; +import { RouteDependencies } from '../../../types'; + import { registerGetAllRoute, registerGetOneRoute } from './register_get_routes'; import { registerDeleteRoute } from './register_delete_route'; import { registerCreateRoute } from './register_create_route'; import { registerUpdateRoute } from './register_update_route'; -export function registerTemplateRoutes(router: Router, server: any) { - registerGetAllRoute(router, server); - registerGetOneRoute(router, server); - registerDeleteRoute(router); - registerCreateRoute(router); - registerUpdateRoute(router); +export function registerTemplateRoutes(dependencies: RouteDependencies) { + registerGetAllRoute(dependencies); + registerGetOneRoute(dependencies); + registerDeleteRoute(dependencies); + registerCreateRoute(dependencies); + registerUpdateRoute(dependencies); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_update_route.ts b/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_update_route.ts index 15590e2acbe7..e7f541fa67f8 100644 --- a/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_update_route.ts +++ b/x-pack/legacy/plugins/index_management/server/routes/api/templates/register_update_route.ts @@ -3,35 +3,65 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ +import { schema } from '@kbn/config-schema'; -import { Router, RouterRouteHandler } from '../../../../../../server/lib/create_router'; import { Template, TemplateEs } from '../../../../common/types'; import { serializeTemplate } from '../../../../common/lib'; +import { RouteDependencies } from '../../../types'; +import { addBasePath } from '../index'; +import { templateSchema } from './validate_schemas'; -const handler: RouterRouteHandler = async (req, callWithRequest) => { - const { name } = req.params; - const template = req.payload as Template; - const serializedTemplate = serializeTemplate(template) as TemplateEs; +const bodySchema = templateSchema; +const paramsSchema = schema.object({ + name: schema.string(), +}); - const { order, index_patterns, version, settings, mappings, aliases } = serializedTemplate; - - // Verify the template exists (ES will throw 404 if not) - await callWithRequest('indices.existsTemplate', { name }); - - // Next, update index template - return await callWithRequest('indices.putTemplate', { - name, - order, - body: { - index_patterns, - version, - settings, - mappings, - aliases, +export function registerUpdateRoute({ router, license, lib }: RouteDependencies) { + router.put( + { + path: addBasePath('/templates/{name}'), + validate: { body: bodySchema, params: paramsSchema }, }, - }); -}; + license.guardApiRoute(async (ctx, req, res) => { + const { callAsCurrentUser } = ctx.core.elasticsearch.dataClient; + const { name } = req.params as typeof paramsSchema.type; + const template = req.body as Template; + const serializedTemplate = serializeTemplate(template) as TemplateEs; -export function registerUpdateRoute(router: Router) { - router.put('templates/{name}', handler); + const { order, index_patterns, version, settings, mappings, aliases } = serializedTemplate; + + // Verify the template exists (ES will throw 404 if not) + const doesExist = await callAsCurrentUser('indices.existsTemplate', { name }); + + if (!doesExist) { + return res.notFound(); + } + + try { + // Next, update index template + const response = await callAsCurrentUser('indices.putTemplate', { + name, + order, + body: { + index_patterns, + version, + settings, + mappings, + aliases, + }, + }); + + return res.ok({ body: response }); + } catch (e) { + if (lib.isEsError(e)) { + return res.customError({ + statusCode: e.statusCode, + body: e, + }); + } + // Case: default + return res.internalError({ body: e }); + } + }) + ); } diff --git a/x-pack/legacy/plugins/index_management/server/routes/api/templates/validate_schemas.ts b/x-pack/legacy/plugins/index_management/server/routes/api/templates/validate_schemas.ts new file mode 100644 index 000000000000..fb5d41870eec --- /dev/null +++ b/x-pack/legacy/plugins/index_management/server/routes/api/templates/validate_schemas.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { schema } from '@kbn/config-schema'; + +export const templateSchema = schema.object({ + name: schema.string(), + indexPatterns: schema.arrayOf(schema.string()), + version: schema.maybe(schema.number()), + order: schema.maybe(schema.number()), + settings: schema.maybe(schema.object({}, { allowUnknowns: true })), + aliases: schema.maybe(schema.object({}, { allowUnknowns: true })), + mappings: schema.maybe(schema.object({}, { allowUnknowns: true })), + ilmPolicy: schema.maybe( + schema.object({ + name: schema.maybe(schema.string()), + rollover_alias: schema.maybe(schema.string()), + }) + ), + isManaged: schema.maybe(schema.boolean()), +}); diff --git a/x-pack/legacy/plugins/index_management/server/routes/helpers.ts b/x-pack/legacy/plugins/index_management/server/routes/helpers.ts new file mode 100644 index 000000000000..6cd4b0dc80e2 --- /dev/null +++ b/x-pack/legacy/plugins/index_management/server/routes/helpers.ts @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +const extractCausedByChain = (causedBy: any = {}, accumulator: any[] = []): any => { + const { reason, caused_by } = causedBy; // eslint-disable-line @typescript-eslint/camelcase + + if (reason) { + accumulator.push(reason); + } + + // eslint-disable-next-line @typescript-eslint/camelcase + if (caused_by) { + return extractCausedByChain(caused_by, accumulator); + } + + return accumulator; +}; + +/** + * Wraps an error thrown by the ES JS client into a Boom error response and returns it + * + * @param err Object Error thrown by ES JS client + * @param statusCodeToMessageMap Object Optional map of HTTP status codes => error messages + * @return Object Boom error response + */ +export const wrapEsError = (err: any, statusCodeToMessageMap: any = {}) => { + const { statusCode, response } = err; + + const { + error: { + root_cause = [], // eslint-disable-line @typescript-eslint/camelcase + caused_by = {}, // eslint-disable-line @typescript-eslint/camelcase + } = {}, + } = JSON.parse(response); + + // If no custom message if specified for the error's status code, just + // wrap the error as a Boom error response, include the additional information from ES, and return it + if (!statusCodeToMessageMap[statusCode]) { + // const boomError = Boom.boomify(err, { statusCode }); + const error: any = { statusCode }; + + // The caused_by chain has the most information so use that if it's available. If not then + // settle for the root_cause. + const causedByChain = extractCausedByChain(caused_by); + const defaultCause = root_cause.length ? extractCausedByChain(root_cause[0]) : undefined; + + error.cause = causedByChain.length ? causedByChain : defaultCause; + return error; + } + + // Otherwise, use the custom message to create a Boom error response and + // return it + const message = statusCodeToMessageMap[statusCode]; + return { message, statusCode }; +}; diff --git a/x-pack/legacy/plugins/index_management/server/routes/index.ts b/x-pack/legacy/plugins/index_management/server/routes/index.ts new file mode 100644 index 000000000000..870cfa36ecc6 --- /dev/null +++ b/x-pack/legacy/plugins/index_management/server/routes/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { RouteDependencies } from '../types'; + +import { registerIndicesRoutes } from './api/indices'; +import { registerTemplateRoutes } from './api/templates'; +import { registerMappingRoute } from './api/mapping'; +import { registerSettingsRoutes } from './api/settings'; +import { registerStatsRoute } from './api/stats'; + +export class ApiRoutes { + setup(dependencies: RouteDependencies) { + registerIndicesRoutes(dependencies); + registerTemplateRoutes(dependencies); + registerSettingsRoutes(dependencies); + registerStatsRoute(dependencies); + registerMappingRoute(dependencies); + } + + start() {} + stop() {} +} diff --git a/x-pack/legacy/plugins/index_management/server/services/index.ts b/x-pack/legacy/plugins/index_management/server/services/index.ts new file mode 100644 index 000000000000..f1a2c2c00993 --- /dev/null +++ b/x-pack/legacy/plugins/index_management/server/services/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { License } from './license'; + +export { IndexDataEnricher, Enricher } from './index_data_enricher'; diff --git a/x-pack/legacy/plugins/index_management/server/services/index_data_enricher.ts b/x-pack/legacy/plugins/index_management/server/services/index_data_enricher.ts new file mode 100644 index 000000000000..7a62ce9f7a3c --- /dev/null +++ b/x-pack/legacy/plugins/index_management/server/services/index_data_enricher.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Index, CallAsCurrentUser } from '../types'; + +export type Enricher = (indices: Index[], callAsCurrentUser: CallAsCurrentUser) => Promise; + +export class IndexDataEnricher { + private readonly _enrichers: Enricher[] = []; + + public add(enricher: Enricher) { + this._enrichers.push(enricher); + } + + public enrichIndices = async ( + indices: Index[], + callAsCurrentUser: CallAsCurrentUser + ): Promise => { + let enrichedIndices = indices; + + for (let i = 0; i < this.enrichers.length; i++) { + const dataEnricher = this.enrichers[i]; + try { + const dataEnricherResponse = await dataEnricher(enrichedIndices, callAsCurrentUser); + enrichedIndices = dataEnricherResponse; + } catch (e) { + // silently swallow enricher response errors + } + } + + return enrichedIndices; + }; + + public get enrichers() { + return this._enrichers; + } +} diff --git a/x-pack/legacy/plugins/index_management/server/services/license.ts b/x-pack/legacy/plugins/index_management/server/services/license.ts new file mode 100644 index 000000000000..fc284a0e3eb6 --- /dev/null +++ b/x-pack/legacy/plugins/index_management/server/services/license.ts @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { Logger } from 'src/core/server'; +import { + KibanaRequest, + KibanaResponseFactory, + RequestHandler, + RequestHandlerContext, +} from 'kibana/server'; + +import { LicensingPluginSetup } from '../../../../../plugins/licensing/server'; +import { LicenseType } from '../../../../../plugins/licensing/common/types'; +import { LICENSE_CHECK_STATE } from '../../../../../plugins/licensing/common/types'; + +export interface LicenseStatus { + isValid: boolean; + message?: string; +} + +interface SetupSettings { + pluginId: string; + minimumLicenseType: LicenseType; + defaultErrorMessage: string; +} + +export class License { + private licenseStatus: LicenseStatus = { + isValid: false, + message: 'Invalid License', + }; + + setup( + { pluginId, minimumLicenseType, defaultErrorMessage }: SetupSettings, + { licensing, logger }: { licensing: LicensingPluginSetup; logger: Logger } + ) { + licensing.license$.subscribe(license => { + const { state, message } = license.check(pluginId, minimumLicenseType); + const hasRequiredLicense = state === LICENSE_CHECK_STATE.Valid; + + if (hasRequiredLicense) { + this.licenseStatus = { isValid: true }; + } else { + this.licenseStatus = { + isValid: false, + message: message || defaultErrorMessage, + }; + if (message) { + logger.info(message); + } + } + }); + } + + guardApiRoute(handler: RequestHandler) { + const license = this; + + return function licenseCheck( + ctx: RequestHandlerContext, + request: KibanaRequest, + response: KibanaResponseFactory + ) { + const licenseStatus = license.getStatus(); + + if (!licenseStatus.isValid) { + return response.customError({ + body: { + message: licenseStatus.message || '', + }, + statusCode: 403, + }); + } + + return handler(ctx, request, response); + }; + } + + getStatus() { + return this.licenseStatus; + } +} diff --git a/x-pack/legacy/plugins/index_management/server/types.ts b/x-pack/legacy/plugins/index_management/server/types.ts new file mode 100644 index 000000000000..fbc39b88a462 --- /dev/null +++ b/x-pack/legacy/plugins/index_management/server/types.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { ScopedClusterClient, IRouter } from 'src/core/server'; +import { LicensingPluginSetup } from '../../../../plugins/licensing/server'; +import { License, IndexDataEnricher } from './services'; +import { isEsError } from './lib/is_es_error'; + +export interface Dependencies { + licensing: LicensingPluginSetup; +} + +export interface RouteDependencies { + router: IRouter; + license: License; + indexDataEnricher: IndexDataEnricher; + lib: { + isEsError: typeof isEsError; + }; +} + +export interface Index { + health: string; + status: string; + name: string; + uuid: string; + primary: string; + replica: string; + documents: any; + size: any; + isFrozen: boolean; + aliases: string | string[]; + [key: string]: any; +} + +export type CallAsCurrentUser = ScopedClusterClient['callAsCurrentUser']; diff --git a/x-pack/test/api_integration/apis/management/index_management/indices.js b/x-pack/test/api_integration/apis/management/index_management/indices.js index 5ffab7e057aa..7195b8680a28 100644 --- a/x-pack/test/api_integration/apis/management/index_management/indices.js +++ b/x-pack/test/api_integration/apis/management/index_management/indices.js @@ -104,7 +104,7 @@ export default function({ getService }) { it('should require index or indices to be provided', async () => { const { body } = await deleteIndex().expect(400); - expect(body.message).to.contain('index / indices is missing'); + expect(body.message).to.contain('expected value of type [string]'); }); }); @@ -144,7 +144,7 @@ export default function({ getService }) { it('should allow to define the number of segments', async () => { const index = await createIndex(); - await forceMerge(index, { max_num_segments: 1 }).expect(200); + await forceMerge(index, { maxNumSegments: 1 }).expect(200); }); }); diff --git a/x-pack/test/api_integration/apis/management/index_management/templates.js b/x-pack/test/api_integration/apis/management/index_management/templates.js index b404f7336738..d9344846ebb9 100644 --- a/x-pack/test/api_integration/apis/management/index_management/templates.js +++ b/x-pack/test/api_integration/apis/management/index_management/templates.js @@ -92,14 +92,16 @@ export default function({ getService }) { await createTemplate(payload).expect(409); }); - it('should handle ES errors', async () => { + it('should validate the request payload', async () => { const templateName = `template-${getRandomString()}`; const payload = getTemplatePayload(templateName); delete payload.indexPatterns; // index patterns are required const { body } = await createTemplate(payload); - expect(body.message).to.contain('index patterns are missing'); + expect(body.message).to.contain( + '[request body.indexPatterns]: expected value of type [array] ' + ); }); });