in x-pack/solutions/search/plugins/enterprise_search/server/routes/enterprise_search/indices.ts [74:1346]
export function registerIndexRoutes({ router, log, ml }: RouteDependencies) {
router.get(
{
path: '/internal/enterprise_search/search_indices',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: false,
},
elasticsearchErrorHandler(log, async (context, _, response) => {
const { client } = (await context.core).elasticsearch;
const patterns: AlwaysShowPattern = {
alias_pattern: 'search-',
index_pattern: '.ent-search-engine-documents',
};
const indices = await fetchSearchIndices(client, patterns);
return response.ok({
body: indices,
headers: { 'content-type': 'application/json' },
});
})
);
router.get(
{
path: '/internal/enterprise_search/indices',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
query: schema.object({
from: schema.number({ defaultValue: 0, min: 0 }),
only_show_search_optimized_indices: schema.maybe(schema.boolean()),
return_hidden_indices: schema.maybe(schema.boolean()),
search_query: schema.maybe(schema.string()),
size: schema.number({ defaultValue: 10, min: 0 }),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const {
from,
only_show_search_optimized_indices: onlyShowSearchOptimizedIndices,
size,
return_hidden_indices: returnHiddenIndices,
search_query: searchQuery,
} = request.query;
const { client } = (await context.core).elasticsearch;
const { indexNames, indices, totalResults } = await fetchIndices(
client,
searchQuery,
!!returnHiddenIndices,
!!onlyShowSearchOptimizedIndices,
from,
size
);
let connectors: Connector[] = [];
// If the user doesn't have permissions, fetchConnectors will error out. We still want to return indices in that case.
try {
connectors = await fetchConnectors(client.asCurrentUser, indexNames);
} catch {
connectors = [];
}
const enrichedIndices = indices.map((index) => ({
...index,
connector: connectors.find((connector) => connector.index_name === index.name),
}));
return response.ok({
body: {
indices: enrichedIndices,
meta: {
page: {
from,
size,
total: totalResults,
},
},
},
headers: { 'content-type': 'application/json' },
});
})
);
router.get(
{
path: '/internal/enterprise_search/indices/{indexName}',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
indexName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const { client } = (await context.core).elasticsearch;
try {
const index = await fetchIndex(client, indexName, log);
return response.ok({
body: index,
headers: { 'content-type': 'application/json' },
});
} catch (error) {
if (isIndexNotFoundException(error)) {
return createError({
errorCode: ErrorCode.INDEX_NOT_FOUND,
message: 'Could not find index',
response,
statusCode: 404,
});
}
throw error;
}
})
);
router.delete(
{
path: '/internal/enterprise_search/indices/{indexName}',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
indexName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const { client } = (await context.core).elasticsearch;
try {
let connector: Connector | undefined;
// users without permissions to fetch connectors should still see a result
try {
connector = await fetchConnectorByIndexName(client.asCurrentUser, indexName);
} catch (error) {
log.error(`Error fetching connector for index ${indexName}: ${error}`);
}
if (connector) {
if (connector.service_type === CRAWLER_SERVICE_TYPE) {
await deleteConnectorById(client.asCurrentUser, connector.id);
} else {
// detach the deleted index without removing the connector
await updateConnectorIndexName(client.asCurrentUser, connector.id, null);
if (connector.api_key_id) {
await client.asCurrentUser.security.invalidateApiKey({ ids: [connector.api_key_id] });
}
if (connector.api_key_secret_id) {
await deleteConnectorSecret(client.asCurrentUser, connector.api_key_secret_id);
}
}
}
await deleteIndexPipelines(client, indexName);
await deleteAccessControlIndex(client, indexName);
await client.asCurrentUser.indices.delete({ index: indexName });
return response.ok({
body: {},
headers: { 'content-type': 'application/json' },
});
} catch (error) {
if (isIndexNotFoundException(error)) {
return createError({
errorCode: ErrorCode.INDEX_NOT_FOUND,
message: 'Could not find index',
response,
statusCode: 404,
});
}
throw error;
}
})
);
router.get(
{
path: '/internal/enterprise_search/indices/{indexName}/exists',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
indexName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const { client } = (await context.core).elasticsearch;
let indexExists: boolean;
try {
indexExists = await client.asCurrentUser.indices.exists({ index: indexName });
} catch (e) {
log.warn(
i18n.translate('xpack.enterpriseSearch.server.routes.indices.existsErrorLogMessage', {
defaultMessage: 'An error occurred while resolving request to {requestUrl}',
values: {
requestUrl: request.url.toString(),
},
})
);
log.warn(e);
indexExists = false;
}
return response.ok({
body: {
exists: indexExists,
},
headers: { 'content-type': 'application/json' },
});
})
);
router.post(
{
path: '/internal/enterprise_search/indices/{indexName}/api_key',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
body: schema.object({
is_native: schema.boolean(),
}),
params: schema.object({
indexName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const { is_native: isNative } = request.body;
const { client } = (await context.core).elasticsearch;
const apiKey = await generateApiKey(client, indexName, isNative);
return response.ok({
body: apiKey,
headers: { 'content-type': 'application/json' },
});
})
);
router.post(
{
path: '/internal/enterprise_search/indices/{indexName}/pipelines',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
indexName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const { client } = (await context.core).elasticsearch;
const createResult = await createIndexPipelineDefinitions(indexName, client.asCurrentUser);
return response.ok({
body: createResult,
headers: { 'content-type': 'application/json' },
});
})
);
router.delete(
{
path: '/internal/enterprise_search/indices/{indexName}/pipelines',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
indexName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const { client } = (await context.core).elasticsearch;
const body = await revertCustomPipeline(client, indexName);
return response.ok({
body,
headers: { 'content-type': 'application/json' },
});
})
);
router.get(
{
path: '/internal/enterprise_search/indices/{indexName}/pipelines',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
indexName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const { client } = (await context.core).elasticsearch;
const [defaultPipeline, customPipelines] = await Promise.all([
getPipeline(DEFAULT_PIPELINE_NAME, client).catch(() => ({})),
getCustomPipelines(indexName, client),
]);
return response.ok({
body: {
...defaultPipeline,
...customPipelines,
},
headers: { 'content-type': 'application/json' },
});
})
);
router.get(
{
path: '/internal/enterprise_search/indices/{indexName}/pipeline_parameters',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
indexName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const { client } = (await context.core).elasticsearch;
const body = await getIndexPipelineParameters(indexName, client);
return response.ok({
body,
headers: { 'content-type': 'application/json' },
});
})
);
router.get(
{
path: '/internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
indexName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const {
elasticsearch: { client },
savedObjects: { client: savedObjectsClient },
} = await context.core;
const trainedModelsProvider = ml
? ml.trainedModelsProvider(request, savedObjectsClient)
: undefined;
const mlInferencePipelineProcessorConfigs = await fetchMlInferencePipelineProcessors(
client.asCurrentUser,
trainedModelsProvider,
indexName
);
return response.ok({
body: mlInferencePipelineProcessorConfigs,
headers: { 'content-type': 'application/json' },
});
})
);
router.post(
{
path: '/internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
indexName: schema.string(),
}),
body: schema.object({
field_mappings: schema.maybe(
schema.arrayOf(
schema.object({ sourceField: schema.string(), targetField: schema.string() })
)
),
model_id: schema.string(),
pipeline_definition: schema.maybe(
schema.object({
description: schema.maybe(schema.string()),
processors: schema.arrayOf(schema.any()),
version: schema.number(),
})
),
pipeline_name: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const { client } = (await context.core).elasticsearch;
const {
model_id: modelId,
pipeline_name: pipelineName,
pipeline_definition: pipelineDefinition,
field_mappings: fieldMappings,
} = request.body;
try {
// Create the sub-pipeline for inference
const createPipelineResult = await preparePipelineAndIndexForMlInference(
indexName,
pipelineName,
pipelineDefinition,
modelId,
fieldMappings,
client.asCurrentUser
);
return response.ok({
body: {
created: createPipelineResult.pipeline_id,
mapping_updated: createPipelineResult.mapping_updated,
},
headers: { 'content-type': 'application/json' },
});
} catch (error) {
// Handle scenario where pipeline already exists
if ((error as Error).message === ErrorCode.PIPELINE_ALREADY_EXISTS) {
return createError({
errorCode: (error as Error).message as ErrorCode,
message: `
A pipeline with the name "${getPrefixedInferencePipelineProcessorName(pipelineName)}"
already exists. Pipelines names are unique within a deployment. Consider adding the
index name for uniqueness.
`,
response,
statusCode: 409,
});
}
if (fieldMappings && (error as Error).message === ErrorCode.MAPPING_UPDATE_FAILED) {
return createError({
errorCode: (error as Error).message as ErrorCode,
message:
'One or more target fields for this pipeline already exist with a type that is incompatible with the specified model. Ensure that each target field is unique and not already in use.',
response,
statusCode: 409,
});
}
throw error;
}
})
);
router.post(
{
path: '/internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors/attach',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
body: schema.object({
pipeline_name: schema.string(),
}),
params: schema.object({
indexName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const { client } = (await context.core).elasticsearch;
const { pipeline_name: pipelineName } = request.body;
let attachMlInferencePipelineResult: AttachMlInferencePipelineResponse | undefined;
try {
attachMlInferencePipelineResult = await attachMlInferencePipeline(
indexName,
pipelineName,
client.asCurrentUser
);
} catch (error) {
throw error;
}
return response.ok({
body: {
...attachMlInferencePipelineResult,
created: false,
},
headers: { 'content-type': 'application/json' },
});
})
);
router.post(
{
path: '/internal/enterprise_search/indices',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
body: schema.object({
index_name: schema.string(),
language: schema.maybe(schema.nullable(schema.string())),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const { ['index_name']: indexName, language } = request.body;
const { client } = (await context.core).elasticsearch;
const indexExists = await client.asCurrentUser.indices.exists({
index: request.body.index_name,
});
if (indexExists) {
return createError({
errorCode: ErrorCode.INDEX_ALREADY_EXISTS,
message: i18n.translate(
'xpack.enterpriseSearch.server.routes.createApiIndex.indexExistsError',
{
defaultMessage: 'This index already exists',
}
),
response,
statusCode: 409,
});
}
let connector: Connector | undefined;
// users without permissions to fetch connectors should still be able to create an index
try {
connector = await fetchConnectorByIndexName(client.asCurrentUser, indexName);
} catch (error) {
log.error(`Error fetching connector for index ${indexName}: ${error}`);
}
if (connector) {
return createError({
errorCode: ErrorCode.CONNECTOR_DOCUMENT_ALREADY_EXISTS,
message: i18n.translate(
'xpack.enterpriseSearch.server.routes.createApiIndex.connectorExistsError',
{
defaultMessage: 'A connector for this index already exists',
}
),
response,
statusCode: 409,
});
}
const createIndexResponse = await createIndex(client, indexName, language, true);
return response.ok({
body: createIndexResponse,
headers: { 'content-type': 'application/json' },
});
})
);
router.post(
{
path: '/internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors/simulate',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
body: schema.object({
docs: schema.arrayOf(schema.any()),
pipeline: schema.object({
description: schema.maybe(schema.string()),
processors: schema.arrayOf(schema.any()),
}),
}),
params: schema.object({
indexName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const { pipeline, docs } = request.body;
const indexName = decodeURIComponent(request.params.indexName);
const { client } = (await context.core).elasticsearch;
const defaultDescription = `ML inference pipeline for index ${indexName}`;
if (!(await indexOrAliasExists(client, indexName))) {
return createError({
errorCode: ErrorCode.INDEX_NOT_FOUND,
message: i18n.translate(
'xpack.enterpriseSearch.server.routes.indices.pipelines.indexMissingError',
{
defaultMessage: 'The index {indexName} does not exist',
values: {
indexName,
},
}
),
response,
statusCode: 404,
});
}
const simulateRequest: IngestSimulateRequest = {
docs,
pipeline: { description: defaultDescription, ...pipeline },
};
try {
const simulateResult = await client.asCurrentUser.ingest.simulate(simulateRequest);
return response.ok({
body: simulateResult,
headers: { 'content-type': 'application/json' },
});
} catch (e) {
return createError({
errorCode: ErrorCode.UNCAUGHT_EXCEPTION,
message: e.message,
response,
statusCode: 400,
});
}
})
);
router.post(
{
path: '/internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors/simulate/{pipelineName}',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
body: schema.object({
docs: schema.arrayOf(schema.any()),
}),
params: schema.object({
indexName: schema.string(),
pipelineName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const { docs } = request.body;
const indexName = decodeURIComponent(request.params.indexName);
const pipelineName = decodeURIComponent(request.params.pipelineName);
const { client } = (await context.core).elasticsearch;
const [indexExists, pipelinesResponse] = await Promise.all([
indexOrAliasExists(client, indexName),
client.asCurrentUser.ingest.getPipeline({
id: pipelineName,
}),
]);
if (!indexExists) {
return createError({
errorCode: ErrorCode.INDEX_NOT_FOUND,
message: i18n.translate(
'xpack.enterpriseSearch.server.routes.indices.pipelines.indexMissingError',
{
defaultMessage: 'The index {indexName} does not exist',
values: {
indexName,
},
}
),
response,
statusCode: 404,
});
}
if (!(pipelineName in pipelinesResponse)) {
return createError({
errorCode: ErrorCode.PIPELINE_NOT_FOUND,
message: i18n.translate(
'xpack.enterpriseSearch.server.routes.indices.pipelines.pipelineMissingError',
{
defaultMessage: 'The pipeline {pipelineName} does not exist',
values: {
pipelineName,
},
}
),
response,
statusCode: 404,
});
}
const simulateRequest: IngestSimulateRequest = {
docs,
pipeline: pipelinesResponse[pipelineName],
};
try {
const simulateResult = await client.asCurrentUser.ingest.simulate(simulateRequest);
return response.ok({
body: simulateResult,
headers: { 'content-type': 'application/json' },
});
} catch (e) {
return createError({
errorCode: ErrorCode.UNCAUGHT_EXCEPTION,
message: e.message,
response,
statusCode: 400,
});
}
})
);
router.get(
{
path: '/internal/enterprise_search/indices/{indexName}/ml_inference/errors',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
indexName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const { client } = (await context.core).elasticsearch;
let errors: MlInferenceError[] = [];
try {
errors = await getMlInferenceErrors(indexName, client.asCurrentUser);
} catch (error) {
if (!isIndexNotFoundException(error)) {
throw error;
}
}
return response.ok({
body: {
errors,
},
headers: { 'content-type': 'application/json' },
});
})
);
router.put(
{
path: '/internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors/{pipelineName}',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
body: schema.object({
description: schema.maybe(schema.string()),
processors: schema.arrayOf(schema.any()),
}),
params: schema.object({
indexName: schema.string(),
pipelineName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const pipelineBody = request.body;
const indexName = decodeURIComponent(request.params.indexName);
const pipelineName = decodeURIComponent(request.params.pipelineName);
const { client } = (await context.core).elasticsearch;
const pipelineId = getPrefixedInferencePipelineProcessorName(pipelineName);
const defaultDescription = `ML inference pipeline for index ${indexName}`;
if (!(await indexOrAliasExists(client, indexName))) {
return createError({
errorCode: ErrorCode.INDEX_NOT_FOUND,
message: i18n.translate(
'xpack.enterpriseSearch.server.routes.indices.pipelines.indexMissingError',
{
defaultMessage: 'The index {indexName} does not exist',
values: {
indexName,
},
}
),
response,
statusCode: 404,
});
}
const updateRequest: IngestPutPipelineRequest = {
_meta: {
managed: true,
managed_by: 'Enterprise Search',
},
id: pipelineId,
description: defaultDescription,
...pipelineBody,
};
const createResult = await client.asCurrentUser.ingest.putPipeline(updateRequest);
return response.ok({
body: createResult,
headers: { 'content-type': 'application/json' },
});
})
);
router.delete(
{
path: '/internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors/{pipelineName}',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
indexName: schema.string(),
pipelineName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const pipelineName = decodeURIComponent(request.params.pipelineName);
const { client } = (await context.core).elasticsearch;
try {
const deleteResult = await deleteMlInferencePipeline(
indexName,
pipelineName,
client.asCurrentUser
);
return response.ok({
body: deleteResult,
headers: { 'content-type': 'application/json' },
});
} catch (error) {
if (isResourceNotFoundException(error)) {
// return specific message if pipeline doesn't exist
return createError({
errorCode: ErrorCode.RESOURCE_NOT_FOUND,
message: error.meta?.body?.error?.reason,
response,
statusCode: 404,
});
} else if (isPipelineIsInUseException(error)) {
return createError({
errorCode: ErrorCode.PIPELINE_IS_IN_USE,
message: i18n.translate(
'xpack.enterpriseSearch.server.routes.indices.mlInference.pipelineProcessors.pipelineIsInUseError',
{
defaultMessage:
"Inference pipeline is used in managed pipeline ''{pipelineName}'' of a different index",
values: {
pipelineName: error.pipelineName,
},
}
),
response,
statusCode: 400,
});
}
// otherwise, let the default handler wrap it
throw error;
}
})
);
router.get(
{
path: '/internal/enterprise_search/indices/{indexName}/ml_inference/history',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
indexName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const { client } = (await context.core).elasticsearch;
let history: MlInferenceHistoryResponse = { history: [] };
try {
history = await fetchMlInferencePipelineHistory(client.asCurrentUser, indexName);
} catch (error) {
if (!isIndexNotFoundException(error)) {
throw error;
}
}
return response.ok({
body: history,
headers: { 'content-type': 'application/json' },
});
})
);
router.get(
{
path: '/internal/enterprise_search/pipelines/ml_inference',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const {
elasticsearch: { client },
savedObjects: { client: savedObjectsClient },
} = await context.core;
const trainedModelsProvider = ml
? await ml.trainedModelsProvider(request, savedObjectsClient)
: undefined;
const pipelines = await getMlInferencePipelines(client.asCurrentUser, trainedModelsProvider);
return response.ok({
body: pipelines,
headers: { 'content-type': 'application/json' },
});
})
);
router.get(
{
path: '/internal/enterprise_search/pipelines/{pipelineName}',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
pipelineName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const pipelineName = decodeURIComponent(request.params.pipelineName);
const { client } = (await context.core).elasticsearch;
try {
const pipeline = await getPipeline(pipelineName, client);
return response.ok({
body: pipeline,
headers: { 'content-type': 'application/json' },
});
} catch (error) {
if (isNotFoundException(error)) {
// return specific message if pipeline doesn't exist
return createError({
errorCode: ErrorCode.PIPELINE_NOT_FOUND,
message: i18n.translate(
'xpack.enterpriseSearch.server.routes.indices.pipelines.pipelineNotFoundError',
{
defaultMessage: 'The pipeline {pipelineName} does not exist',
values: {
pipelineName,
},
}
),
response,
statusCode: 404,
});
}
throw error;
}
})
);
router.delete(
{
path: '/internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors/{pipelineName}/detach',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
indexName: schema.string(),
pipelineName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const indexName = decodeURIComponent(request.params.indexName);
const pipelineName = decodeURIComponent(request.params.pipelineName);
const { client } = (await context.core).elasticsearch;
try {
const detachResult = await detachMlInferencePipeline(
indexName,
pipelineName,
client.asCurrentUser
);
return response.ok({
body: detachResult,
headers: { 'content-type': 'application/json' },
});
} catch (error) {
if (isResourceNotFoundException(error)) {
// return specific message if pipeline doesn't exist
return createError({
errorCode: ErrorCode.RESOURCE_NOT_FOUND,
message: error.meta?.body?.error?.reason,
response,
statusCode: 404,
});
}
// otherwise, let the default handler wrap it
throw error;
}
})
);
router.post(
{
path: '/internal/enterprise_search/ml/models/{modelName}',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
modelName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const modelName = decodeURIComponent(request.params.modelName);
const {
savedObjects: { client: savedObjectsClient },
} = await context.core;
const trainedModelsProvider = ml
? await ml.trainedModelsProvider(request, savedObjectsClient)
: undefined;
try {
const deployResult = await startMlModelDownload(modelName, trainedModelsProvider);
return response.ok({
body: deployResult,
headers: { 'content-type': 'application/json' },
});
} catch (error) {
if (isResourceNotFoundException(error)) {
// return specific message if model doesn't exist
return createError({
errorCode: ErrorCode.RESOURCE_NOT_FOUND,
message: error.meta?.body?.error?.reason,
response,
statusCode: 404,
});
}
// otherwise, let the default handler wrap it
throw error;
}
})
);
router.post(
{
path: '/internal/enterprise_search/ml/models/{modelName}/deploy',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
modelName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const modelName = decodeURIComponent(request.params.modelName);
const {
savedObjects: { client: savedObjectsClient },
} = await context.core;
const trainedModelsProvider = ml
? await ml.trainedModelsProvider(request, savedObjectsClient)
: undefined;
try {
const deployResult = await startMlModelDeployment(modelName, trainedModelsProvider);
return response.ok({
body: deployResult,
headers: { 'content-type': 'application/json' },
});
} catch (error) {
if (isResourceNotFoundException(error)) {
// return specific message if model doesn't exist
return createError({
errorCode: ErrorCode.RESOURCE_NOT_FOUND,
message: error.meta?.body?.error?.reason,
response,
statusCode: 404,
});
}
// otherwise, let the default handler wrap it
throw error;
}
})
);
router.get(
{
path: '/internal/enterprise_search/ml/models',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const {
savedObjects: { client: savedObjectsClient },
} = await context.core;
const trainedModelsProvider = ml
? await ml.trainedModelsProvider(request, savedObjectsClient)
: undefined;
const modelsResult = await fetchMlModels(trainedModelsProvider, log);
return response.ok({
body: modelsResult,
headers: { 'content-type': 'application/json' },
});
})
);
router.get(
{
path: '/internal/enterprise_search/ml/models/{modelName}',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
validate: {
params: schema.object({
modelName: schema.string(),
}),
},
},
elasticsearchErrorHandler(log, async (context, request, response) => {
const modelName = decodeURIComponent(request.params.modelName);
const {
savedObjects: { client: savedObjectsClient },
} = await context.core;
const trainedModelsProvider = ml
? await ml.trainedModelsProvider(request, savedObjectsClient)
: undefined;
try {
const getStatusResult = await getMlModelDeploymentStatus(modelName, trainedModelsProvider);
return response.ok({
body: getStatusResult,
headers: { 'content-type': 'application/json' },
});
} catch (error) {
if (isResourceNotFoundException(error)) {
// return specific message if model doesn't exist
return createError({
errorCode: ErrorCode.RESOURCE_NOT_FOUND,
message: error.meta?.body?.error?.reason,
response,
statusCode: 404,
});
}
// otherwise, let the default handler wrap it
throw error;
}
})
);
}