feat(composite_slo): create schemas and route boilerplates (#158381)

This commit is contained in:
Kevin Delemme 2023-05-25 10:38:14 -04:00 committed by GitHub
parent 43d751e37d
commit 0d2a1083c0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 384 additions and 9 deletions

View file

@ -2097,6 +2097,32 @@
}
}
},
"composite-slo": {
"dynamic": false,
"properties": {
"id": {
"type": "keyword"
},
"name": {
"type": "text"
},
"budgetingMethod": {
"type": "keyword"
},
"compositeMethod": {
"type": "keyword"
},
"sources": {
"properties": {
"id": { "type": "keyword" },
"revision": { "type": "integer" }
}
},
"tags": {
"type": "keyword"
}
}
},
"observability-onboarding-state": {
"properties": {
"state": {

View file

@ -0,0 +1,139 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import * as t from 'io-ts';
import {
budgetingMethodSchema,
compositeSloIdSchema,
dateType,
rollingTimeWindowSchema,
summarySchema,
tagsSchema,
targetSchema,
weightedAverageCompositeMethodSchema,
weightedAverageSourceSchema,
} from '../schema';
const createCompositeSLOParamsSchema = t.type({
body: t.intersection([
t.type({
name: t.string,
timeWindow: rollingTimeWindowSchema,
budgetingMethod: budgetingMethodSchema,
objective: targetSchema,
compositeMethod: weightedAverageCompositeMethodSchema,
sources: t.array(weightedAverageSourceSchema),
}),
t.partial({ id: compositeSloIdSchema, tags: tagsSchema }),
]),
});
const createCompositeSLOResponseSchema = t.type({
id: compositeSloIdSchema,
});
const compositeSLOResponseSchema = t.type({
id: compositeSloIdSchema,
name: t.string,
timeWindow: rollingTimeWindowSchema,
budgetingMethod: budgetingMethodSchema,
objective: targetSchema,
compositeMethod: weightedAverageCompositeMethodSchema,
sources: t.array(weightedAverageSourceSchema),
tags: tagsSchema,
createdAt: dateType,
updatedAt: dateType,
});
const compositeSLOWithSummaryResponseSchema = t.intersection([
compositeSLOResponseSchema,
t.type({ summary: summarySchema }),
]);
const updateCompositeSLOParamsSchema = t.type({
path: t.type({
id: compositeSloIdSchema,
}),
body: t.partial({
name: t.string,
compositeMethod: weightedAverageCompositeMethodSchema,
sources: t.array(weightedAverageSourceSchema),
timeWindow: rollingTimeWindowSchema,
budgetingMethod: budgetingMethodSchema,
objective: targetSchema,
tags: tagsSchema,
}),
});
const updateCompositeSLOResponseSchema = compositeSLOResponseSchema;
const deleteCompositeSLOParamsSchema = t.type({
path: t.type({
id: compositeSloIdSchema,
}),
});
const getCompositeSLOParamsSchema = t.type({
path: t.type({
id: compositeSloIdSchema,
}),
});
const getCompositeSLOResponseSchema = compositeSLOWithSummaryResponseSchema;
const sortDirectionSchema = t.union([t.literal('asc'), t.literal('desc')]);
const sortBySchema = t.literal('creationTime');
const findCompositeSLOParamsSchema = t.partial({
query: t.partial({
name: t.string,
page: t.string,
perPage: t.string,
sortBy: sortBySchema,
sortDirection: sortDirectionSchema,
}),
});
const findCompositeSLOResponseSchema = t.type({
page: t.number,
perPage: t.number,
total: t.number,
results: t.array(compositeSLOWithSummaryResponseSchema),
});
type CreateCompositeSLOInput = t.OutputOf<typeof createCompositeSLOParamsSchema.props.body>; // Raw payload sent by the frontend
type CreateCompositeSLOParams = t.TypeOf<typeof createCompositeSLOParamsSchema.props.body>; // Parsed payload used by the backend
type CreateCompositeSLOResponse = t.TypeOf<typeof createCompositeSLOResponseSchema>; // Raw response sent to the frontend
type GetCompositeSLOResponse = t.OutputOf<typeof getCompositeSLOResponseSchema>;
type FindCompositeSLOParams = t.TypeOf<typeof findCompositeSLOParamsSchema.props.query>;
type FindCompositeSLOResponse = t.OutputOf<typeof findCompositeSLOResponseSchema>;
type UpdateCompositeSLOInput = t.OutputOf<typeof updateCompositeSLOParamsSchema.props.body>;
type UpdateCompositeSLOParams = t.TypeOf<typeof updateCompositeSLOParamsSchema.props.body>;
type UpdateCompositeSLOResponse = t.TypeOf<typeof updateCompositeSLOResponseSchema>;
export {
createCompositeSLOParamsSchema,
deleteCompositeSLOParamsSchema,
findCompositeSLOParamsSchema,
getCompositeSLOParamsSchema,
updateCompositeSLOParamsSchema,
};
export type {
CreateCompositeSLOInput,
CreateCompositeSLOParams,
CreateCompositeSLOResponse,
FindCompositeSLOParams,
FindCompositeSLOResponse,
GetCompositeSLOResponse,
UpdateCompositeSLOInput,
UpdateCompositeSLOParams,
UpdateCompositeSLOResponse,
};

View file

@ -6,4 +6,5 @@
* Side Public License, v 1.
*/
export * from './composite_slo';
export * from './slo';

View file

@ -0,0 +1,42 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import * as t from 'io-ts';
import { dateType } from './common';
import { budgetingMethodSchema, sloIdSchema, tagsSchema, targetSchema } from './slo';
import { rollingTimeWindowSchema } from './time_window';
const compositeSloIdSchema = t.string;
const weightedAverageCompositeMethodSchema = t.literal('weightedAverage');
const weightedAverageSourceSchema = t.type({
id: sloIdSchema,
revision: t.number,
weight: t.number,
});
const compositeSloSchema = t.type({
id: compositeSloIdSchema,
name: t.string,
timeWindow: rollingTimeWindowSchema,
budgetingMethod: budgetingMethodSchema,
compositeMethod: weightedAverageCompositeMethodSchema,
objective: targetSchema,
sources: t.array(weightedAverageSourceSchema),
tags: tagsSchema,
createdAt: dateType,
updatedAt: dateType,
});
export {
weightedAverageSourceSchema,
weightedAverageCompositeMethodSchema,
compositeSloIdSchema,
compositeSloSchema,
};

View file

@ -6,8 +6,9 @@
* Side Public License, v 1.
*/
export * from './slo';
export * from './common';
export * from './indicators';
export * from './composite_slo';
export * from './duration';
export * from './indicators';
export * from './time_window';
export * from './slo';

View file

@ -20,8 +20,10 @@ const budgetingMethodSchema = t.union([
timeslicesBudgetingMethodSchema,
]);
const targetSchema = t.type({ target: t.number });
const objectiveSchema = t.intersection([
t.type({ target: t.number }),
targetSchema,
t.partial({ timesliceTarget: t.number, timesliceWindow: durationType }),
]);
@ -64,5 +66,6 @@ export {
sloSchema,
sloWithSummarySchema,
tagsSchema,
targetSchema,
timeslicesBudgetingMethodSchema,
};

View file

@ -75,6 +75,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
"cases-connector-mappings": "f9d1ac57e484e69506c36a8051e4d61f4a8cfd25",
"cases-telemetry": "f219eb7e26772884342487fc9602cfea07b3cedc",
"cases-user-actions": "483f10db9b3bd1617948d7032a98b7791bf87414",
"composite-slo": "d771c24af50d7ca5667a046b63ed024a4bfd819d",
"config": "179b3e2bc672626aafce3cf92093a113f456af38",
"config-global": "8e8a134a2952df700d7d4ec51abb794bbd4cf6da",
"connector_token": "5a9ac29fe9c740eb114e9c40517245c71706b005",

View file

@ -190,6 +190,7 @@ describe('split .kibana index into multiple system indices', () => {
"cases-connector-mappings",
"cases-telemetry",
"cases-user-actions",
"composite-slo",
"config",
"config-global",
"connector_token",

View file

@ -38,6 +38,7 @@ const previouslyRegisteredTypes = [
'config',
'config-global',
'connector_token',
'composite-slo',
'core-usage-stats',
'csp-rule-template',
'csp_rule',

View file

@ -0,0 +1,16 @@
/*
* 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 * as t from 'io-ts';
import { compositeSloSchema, compositeSloIdSchema } from '@kbn/slo-schema';
type CompositeSLO = t.TypeOf<typeof compositeSloSchema>;
type CompositeSLOId = t.TypeOf<typeof compositeSloIdSchema>;
type StoredCompositeSLO = t.OutputOf<typeof compositeSloSchema>;
export type { CompositeSLO, CompositeSLOId, StoredCompositeSLO };

View file

@ -41,7 +41,7 @@ import { uiSettings } from './ui_settings';
import { registerRoutes } from './routes/register_routes';
import { getObservabilityServerRouteRepository } from './routes/get_global_observability_server_route_repository';
import { casesFeatureId, observabilityFeatureId, sloFeatureId } from '../common';
import { slo, SO_SLO_TYPE } from './saved_objects';
import { compositeSlo, slo, SO_COMPOSITE_SLO_TYPE, SO_SLO_TYPE } from './saved_objects';
import { SLO_RULE_REGISTRATION_CONTEXT } from './common/constants';
import { registerRuleTypes } from './lib/rules/register_rule_types';
import { SLO_BURN_RATE_RULE_ID } from '../common/constants';
@ -187,7 +187,7 @@ export class ObservabilityPlugin implements Plugin<ObservabilityPluginSetup> {
catalogue: [sloFeatureId, 'observability'],
api: ['slo_write', 'slo_read', 'rac'],
savedObject: {
all: [SO_SLO_TYPE],
all: [SO_SLO_TYPE, SO_COMPOSITE_SLO_TYPE],
read: [],
},
alerting: {
@ -206,7 +206,7 @@ export class ObservabilityPlugin implements Plugin<ObservabilityPluginSetup> {
api: ['slo_read', 'rac'],
savedObject: {
all: [],
read: [SO_SLO_TYPE],
read: [SO_SLO_TYPE, SO_COMPOSITE_SLO_TYPE],
},
alerting: {
rule: {
@ -222,6 +222,7 @@ export class ObservabilityPlugin implements Plugin<ObservabilityPluginSetup> {
});
core.savedObjects.registerType(slo);
core.savedObjects.registerType(compositeSlo);
const ruleDataClient = ruleDataService.initializeIndex({
feature: sloFeatureId,

View file

@ -0,0 +1,98 @@
/*
* 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 { badRequest, notImplemented } from '@hapi/boom';
import {
createCompositeSLOParamsSchema,
deleteCompositeSLOParamsSchema,
findCompositeSLOParamsSchema,
getCompositeSLOParamsSchema,
updateCompositeSLOParamsSchema,
} from '@kbn/slo-schema';
import { ObservabilityRequestHandlerContext } from '../../types';
import { createObservabilityServerRoute } from '../create_observability_server_route';
const assertLicenseAtLeastPlatinum = async (context: ObservabilityRequestHandlerContext) => {
const { license } = await context.licensing;
if (!license.hasAtLeast('platinum')) {
throw badRequest('Platinum license or higher is needed to make use of this feature.');
}
};
const createCompositeSLORoute = createObservabilityServerRoute({
endpoint: 'POST /api/observability/composite_slos 2023-05-24',
options: {
tags: ['access:slo_write'],
},
params: createCompositeSLOParamsSchema,
handler: async ({ context }) => {
await assertLicenseAtLeastPlatinum(context);
throw notImplemented();
},
});
const updateCompositeSLORoute = createObservabilityServerRoute({
endpoint: 'PUT /api/observability/composite_slos/{id} 2023-05-24',
options: {
tags: ['access:slo_write'],
},
params: updateCompositeSLOParamsSchema,
handler: async ({ context }) => {
await assertLicenseAtLeastPlatinum(context);
throw notImplemented();
},
});
const deleteCompositeSLORoute = createObservabilityServerRoute({
endpoint: 'DELETE /api/observability/composite_slos/{id} 2023-05-24',
options: {
tags: ['access:slo_write'],
},
params: deleteCompositeSLOParamsSchema,
handler: async ({ context }) => {
await assertLicenseAtLeastPlatinum(context);
throw notImplemented();
},
});
const getCompositeSLORoute = createObservabilityServerRoute({
endpoint: 'GET /api/observability/composite_slos/{id} 2023-05-24',
options: {
tags: ['access:slo_read'],
},
params: getCompositeSLOParamsSchema,
handler: async ({ context }) => {
await assertLicenseAtLeastPlatinum(context);
throw notImplemented();
},
});
const findCompositeSLORoute = createObservabilityServerRoute({
endpoint: 'GET /api/observability/composite_slos 2023-05-24',
options: {
tags: ['access:slo_read'],
},
params: findCompositeSLOParamsSchema,
handler: async ({ context }) => {
await assertLicenseAtLeastPlatinum(context);
throw notImplemented();
},
});
export const compositeSloRouteRepository = {
...createCompositeSLORoute,
...updateCompositeSLORoute,
...deleteCompositeSLORoute,
...getCompositeSLORoute,
...findCompositeSLORoute,
};

View file

@ -5,13 +5,15 @@
* 2.0.
*/
import { compositeSloRouteRepository } from './composite_slo/route';
import { rulesRouteRepository } from './rules/route';
import { slosRouteRepository } from './slo/route';
import { sloRouteRepository } from './slo/route';
export function getObservabilityServerRouteRepository() {
const repository = {
...rulesRouteRepository,
...slosRouteRepository,
...sloRouteRepository,
...compositeSloRouteRepository,
};
return repository;
}

View file

@ -303,7 +303,7 @@ const getSloDiagnosisRoute = createObservabilityServerRoute({
},
});
export const slosRouteRepository = {
export const sloRouteRepository = {
...createSLORoute,
...deleteSLORoute,
...disableSLORoute,

View file

@ -0,0 +1,42 @@
/*
* 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 { SavedObjectsType } from '@kbn/core-saved-objects-server';
import { SavedObject } from '@kbn/core/server';
import { StoredCompositeSLO } from '../domain/models/composite_slo';
export const SO_COMPOSITE_SLO_TYPE = 'composite-slo';
export const compositeSlo: SavedObjectsType = {
name: SO_COMPOSITE_SLO_TYPE,
hidden: false,
namespaceType: 'multiple-isolated',
mappings: {
dynamic: false,
properties: {
id: { type: 'keyword' },
name: { type: 'text' },
budgetingMethod: { type: 'keyword' },
compositeMethod: { type: 'keyword' },
sources: {
properties: {
id: { type: 'keyword' },
revision: { type: 'integer' },
},
},
tags: { type: 'keyword' },
},
},
management: {
displayName: 'Composite SLO',
importableAndExportable: true,
getTitle(compositeSloSavedObject: SavedObject<StoredCompositeSLO>) {
return `Composite SLO: [${compositeSloSavedObject.attributes.name}]`;
},
},
};

View file

@ -6,3 +6,4 @@
*/
export { slo, SO_SLO_TYPE } from './slo';
export { compositeSlo, SO_COMPOSITE_SLO_TYPE } from './composite_slo';