[8.x] separate SLO route functions into different files (#208261) (#208414)

# Backport

This will backport the following commits from `main` to `8.x`:
- [separate SLO route functions into different files
(#208261)](https://github.com/elastic/kibana/pull/208261)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Bailey
Cash","email":"bailey.cash@elastic.co"},"sourceCommit":{"committedDate":"2025-01-27T17:19:01Z","message":"separate
SLO route functions into different files (#208261)\n\nResolves
[#207879](https://github.com/elastic/kibana/issues/207879)\r\n\r\nThis
PR separates the different SLO route functions into separate
files,\r\neach with a single responsibility. The functions are still
exported via\r\na single function,
`getSloRouteRepository`.\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic
Machine
<elasticmachine@users.noreply.github.com>","sha":"a133dc57a7c2e95a080c0026b143472a35b69a1a","branchLabelMapping":{"^v9.0.0$":"main","^v8.18.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","backport:prev-minor","Team:obs-ux-management","v8.18.0"],"title":"separate
SLO route functions into different
files","number":208261,"url":"https://github.com/elastic/kibana/pull/208261","mergeCommit":{"message":"separate
SLO route functions into different files (#208261)\n\nResolves
[#207879](https://github.com/elastic/kibana/issues/207879)\r\n\r\nThis
PR separates the different SLO route functions into separate
files,\r\neach with a single responsibility. The functions are still
exported via\r\na single function,
`getSloRouteRepository`.\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic
Machine
<elasticmachine@users.noreply.github.com>","sha":"a133dc57a7c2e95a080c0026b143472a35b69a1a"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/208261","number":208261,"mergeCommit":{"message":"separate
SLO route functions into different files (#208261)\n\nResolves
[#207879](https://github.com/elastic/kibana/issues/207879)\r\n\r\nThis
PR separates the different SLO route functions into separate
files,\r\neach with a single responsibility. The functions are still
exported via\r\na single function,
`getSloRouteRepository`.\r\n\r\n---------\r\n\r\nCo-authored-by: Elastic
Machine
<elasticmachine@users.noreply.github.com>","sha":"a133dc57a7c2e95a080c0026b143472a35b69a1a"}},{"branch":"8.x","label":"v8.18.0","branchLabelMappingKey":"^v8.18.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Bailey Cash <bailey.cash@elastic.co>
This commit is contained in:
Kibana Machine 2025-01-28 05:57:09 +11:00 committed by GitHub
parent 3bb356821c
commit 37da4873bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 1133 additions and 809 deletions

View file

@ -0,0 +1,79 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { createSLOParamsSchema } from '@kbn/slo-schema';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
import { getSpaceId } from './utils/get_space_id';
import { createTransformGenerators } from '../../services/transform_generators';
import { DefaultSummaryTransformGenerator } from '../../services/summary_transform_generator/summary_transform_generator';
import { executeWithErrorHandler } from '../../errors';
import {
CreateSLO,
DefaultSummaryTransformManager,
DefaultTransformManager,
KibanaSavedObjectsSLORepository,
} from '../../services';
export const createSLORoute = createSloServerRoute({
endpoint: 'POST /api/observability/slos 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: createSLOParamsSchema,
handler: async ({ context, params, logger, request, plugins, corePlugins }) => {
await assertPlatinumLicense(plugins);
const sloContext = await context.slo;
const dataViews = await plugins.dataViews.start();
const core = await context.core;
const userId = core.security.authc.getCurrentUser()?.username!;
const scopedClusterClient = core.elasticsearch.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const soClient = core.savedObjects.client;
const basePath = corePlugins.http.basePath;
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const [spaceId, dataViewsService] = await Promise.all([
getSpaceId(plugins, request),
dataViews.dataViewsServiceFactory(soClient, esClient),
]);
const transformGenerators = createTransformGenerators(
spaceId,
dataViewsService,
sloContext.isServerless
);
const transformManager = new DefaultTransformManager(
transformGenerators,
scopedClusterClient,
logger
);
const summaryTransformManager = new DefaultSummaryTransformManager(
new DefaultSummaryTransformGenerator(),
scopedClusterClient,
logger
);
const createSLO = new CreateSLO(
esClient,
scopedClusterClient,
repository,
transformManager,
summaryTransformManager,
logger,
spaceId,
basePath,
userId
);
return await executeWithErrorHandler(() => createSLO.execute(params.body));
},
});

View file

@ -0,0 +1,32 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { deleteSLOInstancesParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import { DeleteSLOInstances } from '../../services';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
export const deleteSloInstancesRoute = createSloServerRoute({
endpoint: 'POST /api/observability/slos/_delete_instances 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: deleteSLOInstancesParamsSchema,
handler: async ({ response, context, params, plugins }) => {
await assertPlatinumLicense(plugins);
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const deleteSloInstances = new DeleteSLOInstances(esClient);
await executeWithErrorHandler(() => deleteSloInstances.execute(params.body));
return response.noContent();
},
});

View file

@ -0,0 +1,78 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { deleteSLOParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import {
DefaultSummaryTransformManager,
DefaultTransformManager,
DeleteSLO,
KibanaSavedObjectsSLORepository,
} from '../../services';
import { DefaultSummaryTransformGenerator } from '../../services/summary_transform_generator/summary_transform_generator';
import { createTransformGenerators } from '../../services/transform_generators';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
import { getSpaceId } from './utils/get_space_id';
export const deleteSLORoute = createSloServerRoute({
endpoint: 'DELETE /api/observability/slos/{id} 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: deleteSLOParamsSchema,
handler: async ({ request, response, context, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const dataViews = await plugins.dataViews.start();
const sloContext = await context.slo;
const core = await context.core;
const scopedClusterClient = core.elasticsearch.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const soClient = core.savedObjects.client;
const alerting = await plugins.alerting.start();
const rulesClient = await alerting.getRulesClientWithRequest(request);
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
const transformGenerators = createTransformGenerators(
spaceId,
dataViewsService,
sloContext.isServerless
);
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const transformManager = new DefaultTransformManager(
transformGenerators,
scopedClusterClient,
logger
);
const summaryTransformManager = new DefaultSummaryTransformManager(
new DefaultSummaryTransformGenerator(),
scopedClusterClient,
logger
);
const deleteSLO = new DeleteSLO(
repository,
transformManager,
summaryTransformManager,
esClient,
scopedClusterClient,
rulesClient
);
await executeWithErrorHandler(() => deleteSLO.execute(params.path.id));
return response.noContent();
},
});

View file

@ -0,0 +1,66 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { manageSLOParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import {
DefaultSummaryTransformManager,
DefaultTransformManager,
KibanaSavedObjectsSLORepository,
} from '../../services';
import { ManageSLO } from '../../services/manage_slo';
import { DefaultSummaryTransformGenerator } from '../../services/summary_transform_generator/summary_transform_generator';
import { createTransformGenerators } from '../../services/transform_generators';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
import { getSpaceId } from './utils/get_space_id';
export const disableSLORoute = createSloServerRoute({
endpoint: 'POST /api/observability/slos/{id}/disable 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: manageSLOParamsSchema,
handler: async ({ response, request, context, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const dataViews = await plugins.dataViews.start();
const sloContext = await context.slo;
const core = await context.core;
const scopedClusterClient = core.elasticsearch.client;
const soClient = core.savedObjects.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const transformGenerators = createTransformGenerators(
spaceId,
dataViewsService,
sloContext.isServerless
);
const transformManager = new DefaultTransformManager(
transformGenerators,
scopedClusterClient,
logger
);
const summaryTransformManager = new DefaultSummaryTransformManager(
new DefaultSummaryTransformGenerator(),
scopedClusterClient,
logger
);
const manageSLO = new ManageSLO(repository, transformManager, summaryTransformManager);
await executeWithErrorHandler(() => manageSLO.disable(params.path.id));
return response.noContent();
},
});

View file

@ -0,0 +1,67 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { manageSLOParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import {
DefaultSummaryTransformManager,
DefaultTransformManager,
KibanaSavedObjectsSLORepository,
} from '../../services';
import { ManageSLO } from '../../services/manage_slo';
import { DefaultSummaryTransformGenerator } from '../../services/summary_transform_generator/summary_transform_generator';
import { createTransformGenerators } from '../../services/transform_generators';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
import { getSpaceId } from './utils/get_space_id';
export const enableSLORoute = createSloServerRoute({
endpoint: 'POST /api/observability/slos/{id}/enable 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: manageSLOParamsSchema,
handler: async ({ request, response, context, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const dataViews = await plugins.dataViews.start();
const sloContext = await context.slo;
const core = await context.core;
const scopedClusterClient = core.elasticsearch.client;
const soClient = core.savedObjects.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const transformGenerators = createTransformGenerators(
spaceId,
dataViewsService,
sloContext.isServerless
);
const transformManager = new DefaultTransformManager(
transformGenerators,
scopedClusterClient,
logger
);
const summaryTransformManager = new DefaultSummaryTransformManager(
new DefaultSummaryTransformGenerator(),
scopedClusterClient,
logger
);
const manageSLO = new ManageSLO(repository, transformManager, summaryTransformManager);
await executeWithErrorHandler(() => manageSLO.enable(params.path.id));
return response.noContent();
},
});

View file

@ -0,0 +1,36 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { fetchSLOHealthParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import { GetSLOHealth, KibanaSavedObjectsSLORepository } from '../../services';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
export const fetchSloHealthRoute = createSloServerRoute({
endpoint: 'POST /internal/observability/slos/_health',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: fetchSLOHealthParamsSchema,
handler: async ({ context, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const core = await context.core;
const scopedClusterClient = core.elasticsearch.client;
const soClient = core.savedObjects.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const getSLOHealth = new GetSLOHealth(esClient, scopedClusterClient, repository);
return await executeWithErrorHandler(() => getSLOHealth.execute(params.body));
},
});

View file

@ -0,0 +1,31 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { fetchHistoricalSummaryParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import { DefaultHistoricalSummaryClient } from '../../services/historical_summary_client';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
export const fetchHistoricalSummary = createSloServerRoute({
endpoint: 'POST /internal/observability/slos/_historical_summary',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: fetchHistoricalSummaryParamsSchema,
handler: async ({ context, params, plugins }) => {
await assertPlatinumLicense(plugins);
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const historicalSummaryClient = new DefaultHistoricalSummaryClient(esClient);
return await executeWithErrorHandler(() => historicalSummaryClient.fetch(params.body));
},
});

View file

@ -0,0 +1,33 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { findSloDefinitionsParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import { KibanaSavedObjectsSLORepository } from '../../services';
import { FindSLODefinitions } from '../../services/find_slo_definitions';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
export const findSloDefinitionsRoute = createSloServerRoute({
endpoint: 'GET /api/observability/slos/_definitions 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: findSloDefinitionsParamsSchema,
handler: async ({ context, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const soClient = (await context.core).savedObjects.client;
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const findSloDefinitions = new FindSLODefinitions(repository);
return await executeWithErrorHandler(() => findSloDefinitions.execute(params?.query ?? {}));
},
});

View file

@ -0,0 +1,34 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { findSLOGroupsParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import { FindSLOGroups } from '../../services';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
import { getSpaceId } from './utils/get_space_id';
export const findSLOGroupsRoute = createSloServerRoute({
endpoint: 'GET /internal/observability/slos/_groups',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: findSLOGroupsParamsSchema,
handler: async ({ context, request, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const soClient = (await context.core).savedObjects.client;
const coreContext = context.core;
const esClient = (await coreContext).elasticsearch.client.asCurrentUser;
const findSLOGroups = new FindSLOGroups(esClient, soClient, logger, spaceId);
return await executeWithErrorHandler(() => findSLOGroups.execute(params?.query ?? {}));
},
});

View 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
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { findSLOParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import { FindSLO, KibanaSavedObjectsSLORepository } from '../../services';
import { DefaultSummarySearchClient } from '../../services/summary_search_client/summary_search_client';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
import { getSpaceId } from './utils/get_space_id';
export const findSLORoute = createSloServerRoute({
endpoint: 'GET /api/observability/slos 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: findSLOParamsSchema,
handler: async ({ context, request, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const soClient = (await context.core).savedObjects.client;
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const summarySearchClient = new DefaultSummarySearchClient(esClient, soClient, logger, spaceId);
const findSLO = new FindSLO(repository, summarySearchClient);
return await executeWithErrorHandler(() => findSLO.execute(params?.query ?? {}));
},
});

View file

@ -0,0 +1,37 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { errors } from '@elastic/elasticsearch';
import { failedDependency, forbidden } from '@hapi/boom';
import { getGlobalDiagnosis } from '../../services/get_diagnosis';
import { createSloServerRoute } from '../create_slo_server_route';
export const getDiagnosisRoute = createSloServerRoute({
endpoint: 'GET /internal/observability/slos/_diagnosis',
options: { access: 'internal' },
security: {
authz: {
enabled: false,
reason: 'The endpoint is used to diagnose SLOs and does not require any specific privileges.',
},
},
params: undefined,
handler: async ({ context, plugins }) => {
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const licensing = await plugins.licensing.start();
try {
const response = await getGlobalDiagnosis(esClient, licensing);
return response;
} catch (error) {
if (error instanceof errors.ResponseError && error.statusCode === 403) {
throw forbidden('Insufficient Elasticsearch cluster permissions to access feature.');
}
throw failedDependency(error);
}
},
});

View file

@ -0,0 +1,45 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { getSLOGroupingsParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import { KibanaSavedObjectsSLORepository } from '../../services';
import { GetSLOGroupings } from '../../services/get_slo_groupings';
import { SloDefinitionClient } from '../../services/slo_definition_client';
import { getSloSettings } from '../../services/slo_settings';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
import { getSpaceId } from './utils/get_space_id';
export const getSLOGroupingsRoute = createSloServerRoute({
endpoint: 'GET /internal/observability/slos/{id}/_groupings',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: getSLOGroupingsParamsSchema,
handler: async ({ context, params, request, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const soClient = (await context.core).savedObjects.client;
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const [spaceId, settings] = await Promise.all([
getSpaceId(plugins, request),
getSloSettings(soClient),
]);
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const definitionClient = new SloDefinitionClient(repository, esClient, logger);
const getSLOGroupings = new GetSLOGroupings(definitionClient, esClient, settings, spaceId);
return await executeWithErrorHandler(() =>
getSLOGroupings.execute(params.path.id, params.query)
);
},
});

View file

@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { getPreviewDataParamsSchema } from '@kbn/slo-schema';
import { GetPreviewData } from '../../services/get_preview_data';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
import { getSpaceId } from './utils/get_space_id';
export const getPreviewData = createSloServerRoute({
endpoint: 'POST /internal/observability/slos/_preview',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: getPreviewDataParamsSchema,
handler: async ({ request, context, params, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const dataViews = await plugins.dataViews.start();
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const soClient = (await context.core).savedObjects.client;
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
const service = new GetPreviewData(esClient, spaceId, dataViewsService);
return await service.execute(params.body);
},
});

View file

@ -0,0 +1,47 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { getSLOParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import {
DefaultBurnRatesClient,
DefaultSummaryClient,
GetSLO,
KibanaSavedObjectsSLORepository,
} from '../../services';
import { SloDefinitionClient } from '../../services/slo_definition_client';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
import { getSpaceId } from './utils/get_space_id';
export const getSLORoute = createSloServerRoute({
endpoint: 'GET /api/observability/slos/{id} 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: getSLOParamsSchema,
handler: async ({ request, context, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const soClient = (await context.core).savedObjects.client;
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const burnRatesClient = new DefaultBurnRatesClient(esClient);
const summaryClient = new DefaultSummaryClient(esClient, burnRatesClient);
const definitionClient = new SloDefinitionClient(repository, esClient, logger);
const getSLO = new GetSLO(definitionClient, summaryClient);
return await executeWithErrorHandler(() =>
getSLO.execute(params.path.id, spaceId, params.query)
);
},
});

View file

@ -0,0 +1,48 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { getSLOBurnRatesParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import { getBurnRates } from '../../services/get_burn_rates';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
import { getSpaceId } from './utils/get_space_id';
export const getSloBurnRates = createSloServerRoute({
endpoint: 'POST /internal/observability/slos/{id}/_burn_rates',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: getSLOBurnRatesParamsSchema,
handler: async ({ request, context, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const soClient = (await context.core).savedObjects.client;
const { instanceId, windows, remoteName } = params.body;
return await executeWithErrorHandler(() =>
getBurnRates({
instanceId,
spaceId,
windows,
remoteName,
sloId: params.path.id,
services: {
soClient,
esClient,
logger,
},
})
);
},
});

View file

@ -0,0 +1,28 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { executeWithErrorHandler } from '../../errors';
import { getSloSettings } from '../../services/slo_settings';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
export const getSloSettingsRoute = createSloServerRoute({
endpoint: 'GET /internal/slo/settings',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
handler: async ({ context, plugins }) => {
await assertPlatinumLicense(plugins);
const soClient = (await context.core).savedObjects.client;
return await executeWithErrorHandler(() => getSloSettings(soClient));
},
});

View file

@ -0,0 +1,49 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { getOverviewParamsSchema } from '@kbn/slo-schema/src/rest_specs/routes/get_overview';
import { executeWithErrorHandler } from '../../errors';
import { GetSLOsOverview } from '../../services/get_slos_overview';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
import { getSpaceId } from './utils/get_space_id';
export const getSLOsOverview = createSloServerRoute({
endpoint: 'GET /internal/observability/slos/overview',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: getOverviewParamsSchema,
handler: async ({ context, params, request, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const soClient = (await context.core).savedObjects.client;
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const ruleRegistry = await plugins.ruleRegistry.start();
const racClient = await ruleRegistry.getRacClientWithRequest(request);
const spaceId = await getSpaceId(plugins, request);
const alerting = await plugins.alerting.start();
const rulesClient = await alerting.getRulesClientWithRequest(request);
const slosOverview = new GetSLOsOverview(
soClient,
esClient,
spaceId,
logger,
rulesClient,
racClient
);
return await executeWithErrorHandler(() => slosOverview.execute(params?.query ?? {}));
},
});

View file

@ -0,0 +1,28 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { executeWithErrorHandler } from '../../errors';
import { GetSLOSuggestions } from '../../services/get_slo_suggestions';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
export const getSLOSuggestionsRoute = createSloServerRoute({
endpoint: 'GET /internal/observability/slos/suggestions',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
handler: async ({ context, plugins }) => {
await assertPlatinumLicense(plugins);
const soClient = (await context.core).savedObjects.client;
const getSLOSuggestions = new GetSLOSuggestions(soClient);
return await executeWithErrorHandler(() => getSLOSuggestions.execute());
},
});

View file

@ -0,0 +1,76 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { createSLOParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import {
CreateSLO,
DefaultSummaryTransformManager,
DefaultTransformManager,
KibanaSavedObjectsSLORepository,
} from '../../services';
import { DefaultSummaryTransformGenerator } from '../../services/summary_transform_generator/summary_transform_generator';
import { createTransformGenerators } from '../../services/transform_generators';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
import { getSpaceId } from './utils/get_space_id';
export const inspectSLORoute = createSloServerRoute({
endpoint: 'POST /internal/observability/slos/_inspect',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: createSLOParamsSchema,
handler: async ({ context, params, logger, request, plugins, corePlugins }) => {
await assertPlatinumLicense(plugins);
const sloContext = await context.slo;
const dataViews = await plugins.dataViews.start();
const spaceId = await getSpaceId(plugins, request);
const basePath = corePlugins.http.basePath;
const core = await context.core;
const scopedClusterClient = core.elasticsearch.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const username = core.security.authc.getCurrentUser()?.username!;
const soClient = core.savedObjects.client;
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
const transformGenerators = createTransformGenerators(
spaceId,
dataViewsService,
sloContext.isServerless
);
const transformManager = new DefaultTransformManager(
transformGenerators,
scopedClusterClient,
logger
);
const summaryTransformManager = new DefaultSummaryTransformManager(
new DefaultSummaryTransformGenerator(),
scopedClusterClient,
logger
);
const createSLO = new CreateSLO(
esClient,
scopedClusterClient,
repository,
transformManager,
summaryTransformManager,
logger,
spaceId,
basePath,
username
);
return await executeWithErrorHandler(() => createSLO.inspect(params.body));
},
});

View file

@ -0,0 +1,36 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import {
PutSLOSettingsParams,
putSLOServerlessSettingsParamsSchema,
putSLOSettingsParamsSchema,
} from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import { storeSloSettings } from '../../services/slo_settings';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
export const putSloSettings = (isServerless?: boolean) =>
createSloServerRoute({
endpoint: 'PUT /internal/slo/settings',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: isServerless ? putSLOServerlessSettingsParamsSchema : putSLOSettingsParamsSchema,
handler: async ({ context, params, plugins }) => {
await assertPlatinumLicense(plugins);
const soClient = (await context.core).savedObjects.client;
return await executeWithErrorHandler(() =>
storeSloSettings(soClient, params.body as PutSLOSettingsParams)
);
},
});

View file

@ -0,0 +1,75 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { resetSLOParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import {
DefaultSummaryTransformManager,
DefaultTransformManager,
KibanaSavedObjectsSLORepository,
} from '../../services';
import { ResetSLO } from '../../services/reset_slo';
import { DefaultSummaryTransformGenerator } from '../../services/summary_transform_generator/summary_transform_generator';
import { createTransformGenerators } from '../../services/transform_generators';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
import { getSpaceId } from './utils/get_space_id';
export const resetSLORoute = createSloServerRoute({
endpoint: 'POST /api/observability/slos/{id}/_reset 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: resetSLOParamsSchema,
handler: async ({ context, request, params, logger, plugins, corePlugins }) => {
await assertPlatinumLicense(plugins);
const sloContext = await context.slo;
const dataViews = await plugins.dataViews.start();
const spaceId = await getSpaceId(plugins, request);
const core = await context.core;
const scopedClusterClient = core.elasticsearch.client;
const soClient = core.savedObjects.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const basePath = corePlugins.http.basePath;
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const transformGenerators = createTransformGenerators(
spaceId,
dataViewsService,
sloContext.isServerless
);
const transformManager = new DefaultTransformManager(
transformGenerators,
scopedClusterClient,
logger
);
const summaryTransformManager = new DefaultSummaryTransformManager(
new DefaultSummaryTransformGenerator(),
scopedClusterClient,
logger
);
const resetSLO = new ResetSLO(
esClient,
scopedClusterClient,
repository,
transformManager,
summaryTransformManager,
logger,
spaceId,
basePath
);
return await executeWithErrorHandler(() => resetSLO.execute(params.path.id));
},
});

View file

@ -5,815 +5,28 @@
* 2.0.
*/
import { errors } from '@elastic/elasticsearch';
import { failedDependency, forbidden } from '@hapi/boom';
import { KibanaRequest } from '@kbn/core-http-server';
import {
PutSLOSettingsParams,
createSLOParamsSchema,
deleteSLOInstancesParamsSchema,
deleteSLOParamsSchema,
fetchHistoricalSummaryParamsSchema,
fetchSLOHealthParamsSchema,
findSLOGroupsParamsSchema,
findSLOParamsSchema,
findSloDefinitionsParamsSchema,
getPreviewDataParamsSchema,
getSLOBurnRatesParamsSchema,
getSLOGroupingsParamsSchema,
getSLOParamsSchema,
manageSLOParamsSchema,
putSLOServerlessSettingsParamsSchema,
putSLOSettingsParamsSchema,
resetSLOParamsSchema,
updateSLOParamsSchema,
} from '@kbn/slo-schema';
import { getOverviewParamsSchema } from '@kbn/slo-schema/src/rest_specs/routes/get_overview';
import { executeWithErrorHandler } from '../../errors';
import {
CreateSLO,
DefaultBurnRatesClient,
DefaultSummaryClient,
DefaultSummaryTransformManager,
DefaultTransformManager,
DeleteSLO,
DeleteSLOInstances,
FindSLO,
FindSLOGroups,
GetSLO,
GetSLOHealth,
KibanaSavedObjectsSLORepository,
UpdateSLO,
} from '../../services';
import { FindSLODefinitions } from '../../services/find_slo_definitions';
import { getBurnRates } from '../../services/get_burn_rates';
import { getGlobalDiagnosis } from '../../services/get_diagnosis';
import { GetPreviewData } from '../../services/get_preview_data';
import { GetSLOGroupings } from '../../services/get_slo_groupings';
import { GetSLOSuggestions } from '../../services/get_slo_suggestions';
import { GetSLOsOverview } from '../../services/get_slos_overview';
import { DefaultHistoricalSummaryClient } from '../../services/historical_summary_client';
import { ManageSLO } from '../../services/manage_slo';
import { ResetSLO } from '../../services/reset_slo';
import { SloDefinitionClient } from '../../services/slo_definition_client';
import { getSloSettings, storeSloSettings } from '../../services/slo_settings';
import { DefaultSummarySearchClient } from '../../services/summary_search_client/summary_search_client';
import { DefaultSummaryTransformGenerator } from '../../services/summary_transform_generator/summary_transform_generator';
import { createTransformGenerators } from '../../services/transform_generators';
import { createSloServerRoute } from '../create_slo_server_route';
import { SLORoutesDependencies } from '../types';
const assertPlatinumLicense = async (plugins: SLORoutesDependencies['plugins']) => {
const licensing = await plugins.licensing.start();
const hasCorrectLicense = (await licensing.getLicense()).hasAtLeast('platinum');
if (!hasCorrectLicense) {
throw forbidden('Platinum license or higher is needed to make use of this feature.');
}
};
const getSpaceId = async (plugins: SLORoutesDependencies['plugins'], request: KibanaRequest) => {
const spaces = await plugins.spaces.start();
return (await spaces?.spacesService?.getActiveSpace(request))?.id ?? 'default';
};
const createSLORoute = createSloServerRoute({
endpoint: 'POST /api/observability/slos 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: createSLOParamsSchema,
handler: async ({ context, params, logger, request, plugins, corePlugins }) => {
await assertPlatinumLicense(plugins);
const sloContext = await context.slo;
const dataViews = await plugins.dataViews.start();
const core = await context.core;
const userId = core.security.authc.getCurrentUser()?.username!;
const scopedClusterClient = core.elasticsearch.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const soClient = core.savedObjects.client;
const basePath = corePlugins.http.basePath;
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const [spaceId, dataViewsService] = await Promise.all([
getSpaceId(plugins, request),
dataViews.dataViewsServiceFactory(soClient, esClient),
]);
const transformGenerators = createTransformGenerators(
spaceId,
dataViewsService,
sloContext.isServerless
);
const transformManager = new DefaultTransformManager(
transformGenerators,
scopedClusterClient,
logger
);
const summaryTransformManager = new DefaultSummaryTransformManager(
new DefaultSummaryTransformGenerator(),
scopedClusterClient,
logger
);
const createSLO = new CreateSLO(
esClient,
scopedClusterClient,
repository,
transformManager,
summaryTransformManager,
logger,
spaceId,
basePath,
userId
);
return await executeWithErrorHandler(() => createSLO.execute(params.body));
},
});
const inspectSLORoute = createSloServerRoute({
endpoint: 'POST /internal/observability/slos/_inspect',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: createSLOParamsSchema,
handler: async ({ context, params, logger, request, plugins, corePlugins }) => {
await assertPlatinumLicense(plugins);
const sloContext = await context.slo;
const dataViews = await plugins.dataViews.start();
const spaceId = await getSpaceId(plugins, request);
const basePath = corePlugins.http.basePath;
const core = await context.core;
const scopedClusterClient = core.elasticsearch.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const username = core.security.authc.getCurrentUser()?.username!;
const soClient = core.savedObjects.client;
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
const transformGenerators = createTransformGenerators(
spaceId,
dataViewsService,
sloContext.isServerless
);
const transformManager = new DefaultTransformManager(
transformGenerators,
scopedClusterClient,
logger
);
const summaryTransformManager = new DefaultSummaryTransformManager(
new DefaultSummaryTransformGenerator(),
scopedClusterClient,
logger
);
const createSLO = new CreateSLO(
esClient,
scopedClusterClient,
repository,
transformManager,
summaryTransformManager,
logger,
spaceId,
basePath,
username
);
return await executeWithErrorHandler(() => createSLO.inspect(params.body));
},
});
const updateSLORoute = createSloServerRoute({
endpoint: 'PUT /api/observability/slos/{id} 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: updateSLOParamsSchema,
handler: async ({ context, request, params, logger, plugins, corePlugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const dataViews = await plugins.dataViews.start();
const sloContext = await context.slo;
const basePath = corePlugins.http.basePath;
const core = await context.core;
const scopedClusterClient = core.elasticsearch.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const userId = core.security.authc.getCurrentUser()?.username!;
const soClient = core.savedObjects.client;
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const transformGenerators = createTransformGenerators(
spaceId,
dataViewsService,
sloContext.isServerless
);
const transformManager = new DefaultTransformManager(
transformGenerators,
scopedClusterClient,
logger
);
const summaryTransformManager = new DefaultSummaryTransformManager(
new DefaultSummaryTransformGenerator(),
scopedClusterClient,
logger
);
const updateSLO = new UpdateSLO(
repository,
transformManager,
summaryTransformManager,
esClient,
scopedClusterClient,
logger,
spaceId,
basePath,
userId
);
return await executeWithErrorHandler(() => updateSLO.execute(params.path.id, params.body));
},
});
const deleteSLORoute = createSloServerRoute({
endpoint: 'DELETE /api/observability/slos/{id} 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: deleteSLOParamsSchema,
handler: async ({ request, response, context, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const dataViews = await plugins.dataViews.start();
const sloContext = await context.slo;
const core = await context.core;
const scopedClusterClient = core.elasticsearch.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const soClient = core.savedObjects.client;
const alerting = await plugins.alerting.start();
const rulesClient = await alerting.getRulesClientWithRequest(request);
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
const transformGenerators = createTransformGenerators(
spaceId,
dataViewsService,
sloContext.isServerless
);
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const transformManager = new DefaultTransformManager(
transformGenerators,
scopedClusterClient,
logger
);
const summaryTransformManager = new DefaultSummaryTransformManager(
new DefaultSummaryTransformGenerator(),
scopedClusterClient,
logger
);
const deleteSLO = new DeleteSLO(
repository,
transformManager,
summaryTransformManager,
esClient,
scopedClusterClient,
rulesClient
);
await executeWithErrorHandler(() => deleteSLO.execute(params.path.id));
return response.noContent();
},
});
const getSLORoute = createSloServerRoute({
endpoint: 'GET /api/observability/slos/{id} 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: getSLOParamsSchema,
handler: async ({ request, context, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const soClient = (await context.core).savedObjects.client;
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const burnRatesClient = new DefaultBurnRatesClient(esClient);
const summaryClient = new DefaultSummaryClient(esClient, burnRatesClient);
const definitionClient = new SloDefinitionClient(repository, esClient, logger);
const getSLO = new GetSLO(definitionClient, summaryClient);
return await executeWithErrorHandler(() =>
getSLO.execute(params.path.id, spaceId, params.query)
);
},
});
const enableSLORoute = createSloServerRoute({
endpoint: 'POST /api/observability/slos/{id}/enable 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: manageSLOParamsSchema,
handler: async ({ request, response, context, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const dataViews = await plugins.dataViews.start();
const sloContext = await context.slo;
const core = await context.core;
const scopedClusterClient = core.elasticsearch.client;
const soClient = core.savedObjects.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const transformGenerators = createTransformGenerators(
spaceId,
dataViewsService,
sloContext.isServerless
);
const transformManager = new DefaultTransformManager(
transformGenerators,
scopedClusterClient,
logger
);
const summaryTransformManager = new DefaultSummaryTransformManager(
new DefaultSummaryTransformGenerator(),
scopedClusterClient,
logger
);
const manageSLO = new ManageSLO(repository, transformManager, summaryTransformManager);
await executeWithErrorHandler(() => manageSLO.enable(params.path.id));
return response.noContent();
},
});
const disableSLORoute = createSloServerRoute({
endpoint: 'POST /api/observability/slos/{id}/disable 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: manageSLOParamsSchema,
handler: async ({ response, request, context, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const dataViews = await plugins.dataViews.start();
const sloContext = await context.slo;
const core = await context.core;
const scopedClusterClient = core.elasticsearch.client;
const soClient = core.savedObjects.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const transformGenerators = createTransformGenerators(
spaceId,
dataViewsService,
sloContext.isServerless
);
const transformManager = new DefaultTransformManager(
transformGenerators,
scopedClusterClient,
logger
);
const summaryTransformManager = new DefaultSummaryTransformManager(
new DefaultSummaryTransformGenerator(),
scopedClusterClient,
logger
);
const manageSLO = new ManageSLO(repository, transformManager, summaryTransformManager);
await executeWithErrorHandler(() => manageSLO.disable(params.path.id));
return response.noContent();
},
});
const resetSLORoute = createSloServerRoute({
endpoint: 'POST /api/observability/slos/{id}/_reset 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: resetSLOParamsSchema,
handler: async ({ context, request, params, logger, plugins, corePlugins }) => {
await assertPlatinumLicense(plugins);
const sloContext = await context.slo;
const dataViews = await plugins.dataViews.start();
const spaceId = await getSpaceId(plugins, request);
const core = await context.core;
const scopedClusterClient = core.elasticsearch.client;
const soClient = core.savedObjects.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const basePath = corePlugins.http.basePath;
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const transformGenerators = createTransformGenerators(
spaceId,
dataViewsService,
sloContext.isServerless
);
const transformManager = new DefaultTransformManager(
transformGenerators,
scopedClusterClient,
logger
);
const summaryTransformManager = new DefaultSummaryTransformManager(
new DefaultSummaryTransformGenerator(),
scopedClusterClient,
logger
);
const resetSLO = new ResetSLO(
esClient,
scopedClusterClient,
repository,
transformManager,
summaryTransformManager,
logger,
spaceId,
basePath
);
return await executeWithErrorHandler(() => resetSLO.execute(params.path.id));
},
});
const findSLORoute = createSloServerRoute({
endpoint: 'GET /api/observability/slos 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: findSLOParamsSchema,
handler: async ({ context, request, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const soClient = (await context.core).savedObjects.client;
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const summarySearchClient = new DefaultSummarySearchClient(esClient, soClient, logger, spaceId);
const findSLO = new FindSLO(repository, summarySearchClient);
return await executeWithErrorHandler(() => findSLO.execute(params?.query ?? {}));
},
});
const findSLOGroupsRoute = createSloServerRoute({
endpoint: 'GET /internal/observability/slos/_groups',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: findSLOGroupsParamsSchema,
handler: async ({ context, request, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const soClient = (await context.core).savedObjects.client;
const coreContext = context.core;
const esClient = (await coreContext).elasticsearch.client.asCurrentUser;
const findSLOGroups = new FindSLOGroups(esClient, soClient, logger, spaceId);
return await executeWithErrorHandler(() => findSLOGroups.execute(params?.query ?? {}));
},
});
const getSLOSuggestionsRoute = createSloServerRoute({
endpoint: 'GET /internal/observability/slos/suggestions',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
handler: async ({ context, plugins }) => {
await assertPlatinumLicense(plugins);
const soClient = (await context.core).savedObjects.client;
const getSLOSuggestions = new GetSLOSuggestions(soClient);
return await executeWithErrorHandler(() => getSLOSuggestions.execute());
},
});
const deleteSloInstancesRoute = createSloServerRoute({
endpoint: 'POST /api/observability/slos/_delete_instances 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: deleteSLOInstancesParamsSchema,
handler: async ({ response, context, params, plugins }) => {
await assertPlatinumLicense(plugins);
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const deleteSloInstances = new DeleteSLOInstances(esClient);
await executeWithErrorHandler(() => deleteSloInstances.execute(params.body));
return response.noContent();
},
});
const findSloDefinitionsRoute = createSloServerRoute({
endpoint: 'GET /api/observability/slos/_definitions 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: findSloDefinitionsParamsSchema,
handler: async ({ context, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const soClient = (await context.core).savedObjects.client;
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const findSloDefinitions = new FindSLODefinitions(repository);
return await executeWithErrorHandler(() => findSloDefinitions.execute(params?.query ?? {}));
},
});
const fetchHistoricalSummary = createSloServerRoute({
endpoint: 'POST /internal/observability/slos/_historical_summary',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: fetchHistoricalSummaryParamsSchema,
handler: async ({ context, params, plugins }) => {
await assertPlatinumLicense(plugins);
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const historicalSummaryClient = new DefaultHistoricalSummaryClient(esClient);
return await executeWithErrorHandler(() => historicalSummaryClient.fetch(params.body));
},
});
const getSLOGroupingsRoute = createSloServerRoute({
endpoint: 'GET /internal/observability/slos/{id}/_groupings',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: getSLOGroupingsParamsSchema,
handler: async ({ context, params, request, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const soClient = (await context.core).savedObjects.client;
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const [spaceId, settings] = await Promise.all([
getSpaceId(plugins, request),
getSloSettings(soClient),
]);
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const definitionClient = new SloDefinitionClient(repository, esClient, logger);
const getSLOGroupings = new GetSLOGroupings(definitionClient, esClient, settings, spaceId);
return await executeWithErrorHandler(() =>
getSLOGroupings.execute(params.path.id, params.query)
);
},
});
const getDiagnosisRoute = createSloServerRoute({
endpoint: 'GET /internal/observability/slos/_diagnosis',
options: { access: 'internal' },
security: {
authz: {
enabled: false,
reason: 'The endpoint is used to diagnose SLOs and does not require any specific privileges.',
},
},
params: undefined,
handler: async ({ context, plugins }) => {
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const licensing = await plugins.licensing.start();
try {
const response = await getGlobalDiagnosis(esClient, licensing);
return response;
} catch (error) {
if (error instanceof errors.ResponseError && error.statusCode === 403) {
throw forbidden('Insufficient Elasticsearch cluster permissions to access feature.');
}
throw failedDependency(error);
}
},
});
const fetchSloHealthRoute = createSloServerRoute({
endpoint: 'POST /internal/observability/slos/_health',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: fetchSLOHealthParamsSchema,
handler: async ({ context, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const core = await context.core;
const scopedClusterClient = core.elasticsearch.client;
const soClient = core.savedObjects.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const getSLOHealth = new GetSLOHealth(esClient, scopedClusterClient, repository);
return await executeWithErrorHandler(() => getSLOHealth.execute(params.body));
},
});
const getSloBurnRates = createSloServerRoute({
endpoint: 'POST /internal/observability/slos/{id}/_burn_rates',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: getSLOBurnRatesParamsSchema,
handler: async ({ request, context, params, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const soClient = (await context.core).savedObjects.client;
const { instanceId, windows, remoteName } = params.body;
return await executeWithErrorHandler(() =>
getBurnRates({
instanceId,
spaceId,
windows,
remoteName,
sloId: params.path.id,
services: {
soClient,
esClient,
logger,
},
})
);
},
});
const getPreviewData = createSloServerRoute({
endpoint: 'POST /internal/observability/slos/_preview',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: getPreviewDataParamsSchema,
handler: async ({ request, context, params, plugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const dataViews = await plugins.dataViews.start();
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const soClient = (await context.core).savedObjects.client;
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
const service = new GetPreviewData(esClient, spaceId, dataViewsService);
return await service.execute(params.body);
},
});
const getSloSettingsRoute = createSloServerRoute({
endpoint: 'GET /internal/slo/settings',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
handler: async ({ context, plugins }) => {
await assertPlatinumLicense(plugins);
const soClient = (await context.core).savedObjects.client;
return await executeWithErrorHandler(() => getSloSettings(soClient));
},
});
const putSloSettings = (isServerless?: boolean) =>
createSloServerRoute({
endpoint: 'PUT /internal/slo/settings',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: isServerless ? putSLOServerlessSettingsParamsSchema : putSLOSettingsParamsSchema,
handler: async ({ context, params, plugins }) => {
await assertPlatinumLicense(plugins);
const soClient = (await context.core).savedObjects.client;
return await executeWithErrorHandler(() =>
storeSloSettings(soClient, params.body as PutSLOSettingsParams)
);
},
});
const getSLOsOverview = createSloServerRoute({
endpoint: 'GET /internal/observability/slos/overview',
options: { access: 'internal' },
security: {
authz: {
requiredPrivileges: ['slo_read'],
},
},
params: getOverviewParamsSchema,
handler: async ({ context, params, request, logger, plugins }) => {
await assertPlatinumLicense(plugins);
const soClient = (await context.core).savedObjects.client;
const esClient = (await context.core).elasticsearch.client.asCurrentUser;
const ruleRegistry = await plugins.ruleRegistry.start();
const racClient = await ruleRegistry.getRacClientWithRequest(request);
const spaceId = await getSpaceId(plugins, request);
const alerting = await plugins.alerting.start();
const rulesClient = await alerting.getRulesClientWithRequest(request);
const slosOverview = new GetSLOsOverview(
soClient,
esClient,
spaceId,
logger,
rulesClient,
racClient
);
return await executeWithErrorHandler(() => slosOverview.execute(params?.query ?? {}));
},
});
import { fetchSloHealthRoute } from './fetch_health';
import { getSloSettingsRoute } from './get_slo_settings';
import { createSLORoute } from './create_slo';
import { inspectSLORoute } from './inspect_slo';
import { updateSLORoute } from './update_slo';
import { deleteSLORoute } from './delete_slo';
import { enableSLORoute } from './enable_slo';
import { getSLORoute } from './get_slo';
import { deleteSloInstancesRoute } from './delete_instances';
import { disableSLORoute } from './disable_slo';
import { fetchHistoricalSummary } from './fetch_historical_summary';
import { findSLORoute } from './find_slo';
import { findSloDefinitionsRoute } from './find_definitions';
import { findSLOGroupsRoute } from './find_groups';
import { getDiagnosisRoute } from './get_diagnosis';
import { getSLOGroupingsRoute } from './get_groupings';
import { getPreviewData } from './get_preview_data';
import { getSloBurnRates } from './get_slo_burn_rates';
import { getSLOSuggestionsRoute } from './get_suggestions';
import { putSloSettings } from './put_slo_settings';
import { resetSLORoute } from './reset_slo';
import { getSLOsOverview } from './get_slos_overview';
export const getSloRouteRepository = (isServerless?: boolean) => {
return {

View file

@ -0,0 +1,78 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { updateSLOParamsSchema } from '@kbn/slo-schema';
import { executeWithErrorHandler } from '../../errors';
import {
DefaultSummaryTransformManager,
DefaultTransformManager,
KibanaSavedObjectsSLORepository,
UpdateSLO,
} from '../../services';
import { DefaultSummaryTransformGenerator } from '../../services/summary_transform_generator/summary_transform_generator';
import { createTransformGenerators } from '../../services/transform_generators';
import { createSloServerRoute } from '../create_slo_server_route';
import { assertPlatinumLicense } from './utils/assert_platinum_license';
import { getSpaceId } from './utils/get_space_id';
export const updateSLORoute = createSloServerRoute({
endpoint: 'PUT /api/observability/slos/{id} 2023-10-31',
options: { access: 'public' },
security: {
authz: {
requiredPrivileges: ['slo_write'],
},
},
params: updateSLOParamsSchema,
handler: async ({ context, request, params, logger, plugins, corePlugins }) => {
await assertPlatinumLicense(plugins);
const spaceId = await getSpaceId(plugins, request);
const dataViews = await plugins.dataViews.start();
const sloContext = await context.slo;
const basePath = corePlugins.http.basePath;
const core = await context.core;
const scopedClusterClient = core.elasticsearch.client;
const esClient = core.elasticsearch.client.asCurrentUser;
const userId = core.security.authc.getCurrentUser()?.username!;
const soClient = core.savedObjects.client;
const dataViewsService = await dataViews.dataViewsServiceFactory(soClient, esClient);
const repository = new KibanaSavedObjectsSLORepository(soClient, logger);
const transformGenerators = createTransformGenerators(
spaceId,
dataViewsService,
sloContext.isServerless
);
const transformManager = new DefaultTransformManager(
transformGenerators,
scopedClusterClient,
logger
);
const summaryTransformManager = new DefaultSummaryTransformManager(
new DefaultSummaryTransformGenerator(),
scopedClusterClient,
logger
);
const updateSLO = new UpdateSLO(
repository,
transformManager,
summaryTransformManager,
esClient,
scopedClusterClient,
logger,
spaceId,
basePath,
userId
);
return await executeWithErrorHandler(() => updateSLO.execute(params.path.id, params.body));
},
});

View file

@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { forbidden } from '@hapi/boom';
import { SLORoutesDependencies } from '../../types';
export const assertPlatinumLicense = async (plugins: SLORoutesDependencies['plugins']) => {
const licensing = await plugins.licensing.start();
const hasCorrectLicense = (await licensing.getLicense()).hasAtLeast('platinum');
if (!hasCorrectLicense) {
throw forbidden('Platinum license or higher is needed to make use of this feature.');
}
};

View file

@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { KibanaRequest } from '@kbn/core/server';
import { SLORoutesDependencies } from '../../types';
export const getSpaceId = async (
plugins: SLORoutesDependencies['plugins'],
request: KibanaRequest
) => {
const spaces = await plugins.spaces.start();
return (await spaces?.spacesService?.getActiveSpace(request))?.id ?? 'default';
};