mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
# Backport This will backport the following commits from `main` to `8.16`: - [fix(slo): Override transform _id to ensure uniqness (#198610)](https://github.com/elastic/kibana/pull/198610) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Kevin Delemme","email":"kevin.delemme@elastic.co"},"sourceCommit":{"committedDate":"2024-11-01T15:36:41Z","message":"fix(slo): Override transform _id to ensure uniqness (#198610)","sha":"98db4d6f75f05eba1682e0e903bf2d9c909b37f2","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:skip","v9.0.0","backport:prev-minor","ci:project-deploy-observability","Team:obs-ux-management","v8.16.0"],"title":"fix(slo): Override transform _id to ensure uniqness","number":198610,"url":"https://github.com/elastic/kibana/pull/198610","mergeCommit":{"message":"fix(slo): Override transform _id to ensure uniqness (#198610)","sha":"98db4d6f75f05eba1682e0e903bf2d9c909b37f2"}},"sourceBranch":"main","suggestedTargetBranches":["8.16"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/198610","number":198610,"mergeCommit":{"message":"fix(slo): Override transform _id to ensure uniqness (#198610)","sha":"98db4d6f75f05eba1682e0e903bf2d9c909b37f2"}},{"branch":"8.16","label":"v8.16.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT--> Co-authored-by: Kevin Delemme <kevin.delemme@elastic.co>
This commit is contained in:
parent
4cf7f33e7c
commit
ebe9f29b59
9 changed files with 248 additions and 166 deletions
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import * as t from 'io-ts';
|
||||
import { Either } from 'fp-ts/Either';
|
||||
import { allOrAnyStringOrArray, dateType } from './common';
|
||||
import { durationType } from './duration';
|
||||
import { indicatorSchema } from './indicators';
|
||||
|
@ -36,7 +37,35 @@ const groupBySchema = allOrAnyStringOrArray;
|
|||
|
||||
const optionalSettingsSchema = t.partial({ ...settingsSchema.props });
|
||||
const tagsSchema = t.array(t.string);
|
||||
const sloIdSchema = t.string;
|
||||
// id cannot contain special characters and spaces
|
||||
const sloIdSchema = new t.Type<string, string, unknown>(
|
||||
'sloIdSchema',
|
||||
t.string.is,
|
||||
(input, context): Either<t.Errors, string> => {
|
||||
if (typeof input === 'string') {
|
||||
const valid = isValidId(input);
|
||||
if (!valid) {
|
||||
return t.failure(
|
||||
input,
|
||||
context,
|
||||
'Invalid slo id, must be between 8 and 48 characters and contain only letters, numbers, hyphens, and underscores'
|
||||
);
|
||||
}
|
||||
|
||||
return t.success(input);
|
||||
} else {
|
||||
return t.failure(input, context);
|
||||
}
|
||||
},
|
||||
t.identity
|
||||
);
|
||||
|
||||
function isValidId(id: string): boolean {
|
||||
const MIN_ID_LENGTH = 8;
|
||||
const MAX_ID_LENGTH = 48;
|
||||
const validLength = MIN_ID_LENGTH <= id.length && id.length <= MAX_ID_LENGTH;
|
||||
return validLength && /^[a-z0-9-_]+$/.test(id);
|
||||
}
|
||||
|
||||
const sloDefinitionSchema = t.type({
|
||||
id: sloIdSchema,
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
],
|
||||
"kbn_references": [
|
||||
"@kbn/std",
|
||||
"@kbn/io-ts-utils"
|
||||
"@kbn/io-ts-utils",
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*",
|
||||
|
|
|
@ -17,6 +17,12 @@ export const getSLOPipelineTemplate = (slo: SLODefinition) => ({
|
|||
id: getSLOPipelineId(slo.id, slo.revision),
|
||||
description: `Ingest pipeline for SLO rollup data [id: ${slo.id}, revision: ${slo.revision}]`,
|
||||
processors: [
|
||||
{
|
||||
set: {
|
||||
field: '_id',
|
||||
value: `{{{_id}}}-${slo.id}-${slo.revision}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
set: {
|
||||
field: 'event.ingested',
|
||||
|
|
|
@ -12,6 +12,12 @@ Array [
|
|||
"description": "Ingest pipeline for SLO rollup data [id: unique-id, revision: 1]",
|
||||
"id": ".slo-observability.sli.pipeline-unique-id-1",
|
||||
"processors": Array [
|
||||
Object {
|
||||
"set": Object {
|
||||
"field": "_id",
|
||||
"value": "{{{_id}}}-unique-id-1",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"set": Object {
|
||||
"field": "event.ingested",
|
||||
|
|
|
@ -208,6 +208,12 @@ exports[`ResetSLO resets all associated resources 8`] = `
|
|||
"description": "Ingest pipeline for SLO rollup data [id: irrelevant, revision: 1]",
|
||||
"id": ".slo-observability.sli.pipeline-irrelevant-1",
|
||||
"processors": Array [
|
||||
Object {
|
||||
"set": Object {
|
||||
"field": "_id",
|
||||
"value": "{{{_id}}}-irrelevant-1",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"set": Object {
|
||||
"field": "event.ingested",
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Synthetics Availability Transform Generator returns the expected transform params 1`] = `
|
||||
Object {
|
||||
"_meta": Object {
|
||||
"managed": true,
|
||||
"managed_by": "observability",
|
||||
"version": 3.3,
|
||||
},
|
||||
"defer_validation": true,
|
||||
"description": "Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]",
|
||||
"dest": Object {
|
||||
"index": ".slo-observability.sli-v3.3",
|
||||
"pipeline": ".slo-observability.sli.pipeline-irrelevant-1",
|
||||
},
|
||||
"frequency": "1m",
|
||||
"pivot": Object {
|
||||
"aggregations": Object {
|
||||
"slo.denominator": Object {
|
||||
"filter": Object {
|
||||
"term": Object {
|
||||
"summary.final_attempt": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"slo.numerator": Object {
|
||||
"filter": Object {
|
||||
"term": Object {
|
||||
"monitor.status": "up",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"group_by": Object {
|
||||
"@timestamp": Object {
|
||||
"date_histogram": Object {
|
||||
"field": "@timestamp",
|
||||
"fixed_interval": "1m",
|
||||
},
|
||||
},
|
||||
"monitor.config_id": Object {
|
||||
"terms": Object {
|
||||
"field": "config_id",
|
||||
},
|
||||
},
|
||||
"monitor.name": Object {
|
||||
"terms": Object {
|
||||
"field": "monitor.name",
|
||||
},
|
||||
},
|
||||
"observer.geo.name": Object {
|
||||
"terms": Object {
|
||||
"field": "observer.geo.name",
|
||||
},
|
||||
},
|
||||
"observer.name": Object {
|
||||
"terms": Object {
|
||||
"field": "observer.name",
|
||||
},
|
||||
},
|
||||
"slo.groupings.monitor.id": Object {
|
||||
"terms": Object {
|
||||
"field": "monitor.id",
|
||||
},
|
||||
},
|
||||
"slo.groupings.monitor.name": Object {
|
||||
"terms": Object {
|
||||
"field": "monitor.name",
|
||||
},
|
||||
},
|
||||
"slo.groupings.observer.geo.name": Object {
|
||||
"terms": Object {
|
||||
"field": "observer.geo.name",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"settings": Object {
|
||||
"deduce_mappings": false,
|
||||
"unattended": true,
|
||||
},
|
||||
"source": Object {
|
||||
"index": "synthetics-*",
|
||||
"query": Object {
|
||||
"bool": Object {
|
||||
"filter": Array [
|
||||
Object {
|
||||
"term": Object {
|
||||
"summary.final_attempt": true,
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"term": Object {
|
||||
"meta.space_id": "custom-space",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"range": Object {
|
||||
"@timestamp": Object {
|
||||
"gte": "now-7d/d",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
"runtime_mappings": Object {},
|
||||
},
|
||||
"sync": Object {
|
||||
"time": Object {
|
||||
"delay": "1m",
|
||||
"field": "event.ingested",
|
||||
},
|
||||
},
|
||||
"transform_id": "slo-irrelevant-1",
|
||||
}
|
||||
`;
|
|
@ -0,0 +1,73 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Transform Generator builds common runtime mappings and group by with single group by 1`] = `Object {}`;
|
||||
|
||||
exports[`Transform Generator builds common runtime mappings and group by with single group by 2`] = `
|
||||
Object {
|
||||
"@timestamp": Object {
|
||||
"date_histogram": Object {
|
||||
"field": "@timestamp",
|
||||
"fixed_interval": "1m",
|
||||
},
|
||||
},
|
||||
"slo.groupings.example": Object {
|
||||
"terms": Object {
|
||||
"field": "example",
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Transform Generator builds common runtime mappings and group by with single group by 3`] = `Object {}`;
|
||||
|
||||
exports[`Transform Generator builds common runtime mappings and group by with single group by 4`] = `
|
||||
Object {
|
||||
"@timestamp": Object {
|
||||
"date_histogram": Object {
|
||||
"field": "@timestamp",
|
||||
"fixed_interval": "1m",
|
||||
},
|
||||
},
|
||||
"slo.groupings.example": Object {
|
||||
"terms": Object {
|
||||
"field": "example",
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Transform Generator builds common runtime mappings without multi group by 1`] = `Object {}`;
|
||||
|
||||
exports[`Transform Generator builds common runtime mappings without multi group by 2`] = `
|
||||
Object {
|
||||
"@timestamp": Object {
|
||||
"date_histogram": Object {
|
||||
"field": "@timestamp",
|
||||
"fixed_interval": "1m",
|
||||
},
|
||||
},
|
||||
"slo.groupings.example1": Object {
|
||||
"terms": Object {
|
||||
"field": "example1",
|
||||
},
|
||||
},
|
||||
"slo.groupings.example2": Object {
|
||||
"terms": Object {
|
||||
"field": "example2",
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Transform Generator builds empty runtime mappings without group by 1`] = `Object {}`;
|
||||
|
||||
exports[`Transform Generator builds empty runtime mappings without group by 2`] = `
|
||||
Object {
|
||||
"@timestamp": Object {
|
||||
"date_histogram": Object {
|
||||
"field": "@timestamp",
|
||||
"fixed_interval": "1m",
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
|
@ -5,13 +5,12 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { ALL_VALUE } from '@kbn/slo-schema';
|
||||
import { dataViewsService } from '@kbn/data-views-plugin/server/mocks';
|
||||
import { ALL_VALUE } from '@kbn/slo-schema';
|
||||
import { SLODefinition } from '../../domain/models';
|
||||
import { twoMinute } from '../fixtures/duration';
|
||||
import { createSLO, createSyntheticsAvailabilityIndicator } from '../fixtures/slo';
|
||||
import { SyntheticsAvailabilityTransformGenerator } from './synthetics_availability';
|
||||
import { SYNTHETICS_INDEX_PATTERN } from '../../../common/constants';
|
||||
import { twoMinute } from '../fixtures/duration';
|
||||
|
||||
const generator = new SyntheticsAvailabilityTransformGenerator();
|
||||
|
||||
|
@ -22,119 +21,7 @@ describe('Synthetics Availability Transform Generator', () => {
|
|||
const slo = createSLO({ id: 'irrelevant', indicator: createSyntheticsAvailabilityIndicator() });
|
||||
const transform = await generator.getTransformParams(slo, spaceId, dataViewsService);
|
||||
|
||||
expect(transform).toEqual({
|
||||
_meta: {
|
||||
managed: true,
|
||||
managed_by: 'observability',
|
||||
version: 3.3,
|
||||
},
|
||||
defer_validation: true,
|
||||
description: 'Rolled-up SLI data for SLO: irrelevant [id: irrelevant, revision: 1]',
|
||||
dest: {
|
||||
index: '.slo-observability.sli-v3.3',
|
||||
pipeline: '.slo-observability.sli.pipeline-irrelevant-1',
|
||||
},
|
||||
frequency: '1m',
|
||||
pivot: {
|
||||
aggregations: {
|
||||
'slo.denominator': {
|
||||
filter: {
|
||||
term: {
|
||||
'summary.final_attempt': true,
|
||||
},
|
||||
},
|
||||
},
|
||||
'slo.numerator': {
|
||||
filter: {
|
||||
term: {
|
||||
'monitor.status': 'up',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
group_by: {
|
||||
'@timestamp': {
|
||||
date_histogram: {
|
||||
field: '@timestamp',
|
||||
fixed_interval: '1m',
|
||||
},
|
||||
},
|
||||
'monitor.config_id': {
|
||||
terms: {
|
||||
field: 'config_id',
|
||||
},
|
||||
},
|
||||
'monitor.name': {
|
||||
terms: {
|
||||
field: 'monitor.name',
|
||||
},
|
||||
},
|
||||
'observer.name': {
|
||||
terms: {
|
||||
field: 'observer.name',
|
||||
},
|
||||
},
|
||||
'observer.geo.name': {
|
||||
terms: {
|
||||
field: 'observer.geo.name',
|
||||
},
|
||||
},
|
||||
'slo.groupings.monitor.name': {
|
||||
terms: {
|
||||
field: 'monitor.name',
|
||||
},
|
||||
},
|
||||
'slo.groupings.observer.geo.name': {
|
||||
terms: {
|
||||
field: 'observer.geo.name',
|
||||
},
|
||||
},
|
||||
'slo.groupings.monitor.id': {
|
||||
terms: {
|
||||
field: 'monitor.id',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
deduce_mappings: false,
|
||||
unattended: true,
|
||||
},
|
||||
source: {
|
||||
index: SYNTHETICS_INDEX_PATTERN,
|
||||
query: {
|
||||
bool: {
|
||||
filter: [
|
||||
{
|
||||
term: {
|
||||
'summary.final_attempt': true,
|
||||
},
|
||||
},
|
||||
{
|
||||
term: {
|
||||
'meta.space_id': 'custom-space',
|
||||
},
|
||||
},
|
||||
{
|
||||
range: {
|
||||
'@timestamp': {
|
||||
gte: 'now-7d/d',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
runtime_mappings: {},
|
||||
},
|
||||
sync: {
|
||||
time: {
|
||||
delay: '1m',
|
||||
field: 'event.ingested',
|
||||
},
|
||||
},
|
||||
transform_id: 'slo-irrelevant-1',
|
||||
});
|
||||
expect(transform).toMatchSnapshot();
|
||||
expect(transform.source.query?.bool?.filter).toContainEqual({
|
||||
term: {
|
||||
'summary.final_attempt': true,
|
||||
|
|
|
@ -17,19 +17,10 @@ describe('Transform Generator', () => {
|
|||
indicator: createAPMTransactionErrorRateIndicator(),
|
||||
});
|
||||
const commonRuntime = generator.buildCommonRuntimeMappings(slo);
|
||||
|
||||
expect(commonRuntime).toEqual({});
|
||||
expect(commonRuntime).toMatchSnapshot();
|
||||
|
||||
const commonGroupBy = generator.buildCommonGroupBy(slo);
|
||||
|
||||
expect(commonGroupBy).toEqual({
|
||||
'@timestamp': {
|
||||
date_histogram: {
|
||||
field: '@timestamp',
|
||||
fixed_interval: '1m',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(commonGroupBy).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it.each(['example', ['example']])(
|
||||
|
@ -42,24 +33,10 @@ describe('Transform Generator', () => {
|
|||
indicator,
|
||||
});
|
||||
const commonRuntime = generator.buildCommonRuntimeMappings(slo);
|
||||
|
||||
expect(commonRuntime).toEqual({});
|
||||
expect(commonRuntime).toMatchSnapshot();
|
||||
|
||||
const commonGroupBy = generator.buildCommonGroupBy(slo);
|
||||
|
||||
expect(commonGroupBy).toEqual({
|
||||
'@timestamp': {
|
||||
date_histogram: {
|
||||
field: '@timestamp',
|
||||
fixed_interval: '1m',
|
||||
},
|
||||
},
|
||||
'slo.groupings.example': {
|
||||
terms: {
|
||||
field: 'example',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(commonGroupBy).toMatchSnapshot();
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -71,28 +48,9 @@ describe('Transform Generator', () => {
|
|||
indicator,
|
||||
});
|
||||
const commonRuntime = generator.buildCommonRuntimeMappings(slo);
|
||||
|
||||
expect(commonRuntime).toEqual({});
|
||||
expect(commonRuntime).toMatchSnapshot();
|
||||
|
||||
const commonGroupBy = generator.buildCommonGroupBy(slo);
|
||||
|
||||
expect(commonGroupBy).toEqual({
|
||||
'@timestamp': {
|
||||
date_histogram: {
|
||||
field: '@timestamp',
|
||||
fixed_interval: '1m',
|
||||
},
|
||||
},
|
||||
'slo.groupings.example1': {
|
||||
terms: {
|
||||
field: 'example1',
|
||||
},
|
||||
},
|
||||
'slo.groupings.example2': {
|
||||
terms: {
|
||||
field: 'example2',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(commonGroupBy).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue