[Index management] Server-side NP ready (#56829)
This commit is contained in:
parent
bb7e152211
commit
7e9d79754c
|
@ -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);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
7
x-pack/legacy/plugins/index_management/common/index.ts
Normal file
7
x-pack/legacy/plugins/index_management/common/index.ts
Normal file
|
@ -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';
|
|
@ -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);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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<string | undefined> => {
|
||||
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,
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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<IndexMgmtSetup, void, any, any> {
|
||||
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() {}
|
||||
}
|
||||
|
|
|
@ -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;
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<Template['name']>; 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<Template['name']>; 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);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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()),
|
||||
});
|
|
@ -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 };
|
||||
};
|
|
@ -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() {}
|
||||
}
|
|
@ -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';
|
|
@ -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<Index[]>;
|
||||
|
||||
export class IndexDataEnricher {
|
||||
private readonly _enrichers: Enricher[] = [];
|
||||
|
||||
public add(enricher: Enricher) {
|
||||
this._enrichers.push(enricher);
|
||||
}
|
||||
|
||||
public enrichIndices = async (
|
||||
indices: Index[],
|
||||
callAsCurrentUser: CallAsCurrentUser
|
||||
): Promise<Index[]> => {
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
38
x-pack/legacy/plugins/index_management/server/types.ts
Normal file
38
x-pack/legacy/plugins/index_management/server/types.ts
Normal file
|
@ -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'];
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -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] '
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue