mirror of
https://github.com/grafana/grafana.git
synced 2025-02-20 11:48:34 -06:00
Alerting: Add escape and quote support to the matcher name (#83601)
Add escape and quote support to the matcher name
This commit is contained in:
parent
36a19bfa83
commit
11d341d2bb
@ -72,10 +72,36 @@ describe('formAmRouteToAmRoute', () => {
|
||||
|
||||
// Assert
|
||||
expect(amRoute.matchers).toStrictEqual([
|
||||
'foo="bar"',
|
||||
'foo="bar\\"baz"',
|
||||
'foo="bar\\\\baz"',
|
||||
'foo="\\\\bar\\\\baz\\"\\\\"',
|
||||
'"foo"="bar"',
|
||||
'"foo"="bar\\"baz"',
|
||||
'"foo"="bar\\\\baz"',
|
||||
'"foo"="\\\\bar\\\\baz\\"\\\\"',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should quote and escape matcher names', () => {
|
||||
// Arrange
|
||||
const route: FormAmRoute = buildFormAmRoute({
|
||||
id: '1',
|
||||
object_matchers: [
|
||||
{ name: 'foo', operator: MatcherOperator.equal, value: 'bar' },
|
||||
{ name: 'foo with spaces', operator: MatcherOperator.equal, value: 'bar' },
|
||||
{ name: 'foo\\slash', operator: MatcherOperator.equal, value: 'bar' },
|
||||
{ name: 'foo"quote', operator: MatcherOperator.equal, value: 'bar' },
|
||||
{ name: 'fo\\o', operator: MatcherOperator.equal, value: 'ba\\r' },
|
||||
],
|
||||
});
|
||||
|
||||
// Act
|
||||
const amRoute = formAmRouteToAmRoute('mimir-am', route, { id: 'root' });
|
||||
|
||||
// Assert
|
||||
expect(amRoute.matchers).toStrictEqual([
|
||||
'"foo"="bar"',
|
||||
'"foo with spaces"="bar"',
|
||||
'"foo\\\\slash"="bar"',
|
||||
'"foo\\"quote"="bar"',
|
||||
'"fo\\\\o"="ba\\\\r"',
|
||||
]);
|
||||
});
|
||||
|
||||
@ -90,7 +116,7 @@ describe('formAmRouteToAmRoute', () => {
|
||||
const amRoute = formAmRouteToAmRoute('mimir-am', route, { id: 'root' });
|
||||
|
||||
// Assert
|
||||
expect(amRoute.matchers).toStrictEqual(['foo=""']);
|
||||
expect(amRoute.matchers).toStrictEqual(['"foo"=""']);
|
||||
});
|
||||
|
||||
it('should allow matchers with empty values for Grafana AM', () => {
|
||||
@ -173,4 +199,23 @@ describe('amRouteToFormAmRoute', () => {
|
||||
{ name: 'foo', operator: MatcherOperator.equal, value: '\\bar\\baz"\\' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should unquote and unescape matcher names', () => {
|
||||
// Arrange
|
||||
const amRoute = buildAmRoute({
|
||||
matchers: ['"foo"=bar', '"foo with spaces"=bar', '"foo\\\\slash"=bar', '"foo"quote"=bar', '"fo\\\\o"="ba\\\\r"'],
|
||||
});
|
||||
|
||||
// Act
|
||||
const formRoute = amRouteToFormAmRoute(amRoute);
|
||||
|
||||
// Assert
|
||||
expect(formRoute.object_matchers).toStrictEqual([
|
||||
{ name: 'foo', operator: MatcherOperator.equal, value: 'bar' },
|
||||
{ name: 'foo with spaces', operator: MatcherOperator.equal, value: 'bar' },
|
||||
{ name: 'foo\\slash', operator: MatcherOperator.equal, value: 'bar' },
|
||||
{ name: 'foo"quote', operator: MatcherOperator.equal, value: 'bar' },
|
||||
{ name: 'fo\\o', operator: MatcherOperator.equal, value: 'ba\\r' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@ -98,7 +98,7 @@ export const amRouteToFormAmRoute = (route: RouteWithID | Route | undefined): Fo
|
||||
route.matchers
|
||||
?.map((matcher) => matcherToMatcherField(parseMatcher(matcher)))
|
||||
.map(({ name, operator, value }) => ({
|
||||
name,
|
||||
name: unquoteWithUnescape(name),
|
||||
operator,
|
||||
value: unquoteWithUnescape(value),
|
||||
})) ?? [];
|
||||
@ -186,7 +186,7 @@ export const formAmRouteToAmRoute = (
|
||||
// does not exist in upstream AlertManager
|
||||
if (alertManagerSourceName !== GRAFANA_RULES_SOURCE_NAME) {
|
||||
amRoute.matchers = formAmRoute.object_matchers?.map(
|
||||
({ name, operator, value }) => `${name}${operator}${quoteWithEscape(value)}`
|
||||
({ name, operator, value }) => `${quoteWithEscape(name)}${operator}${quoteWithEscape(value)}`
|
||||
);
|
||||
amRoute.object_matchers = undefined;
|
||||
} else {
|
||||
|
@ -137,9 +137,10 @@ export const matcherFormatter = {
|
||||
return `${name} ${operator} ${formattedValue}`;
|
||||
},
|
||||
unquote: ([name, operator, value]: ObjectMatcher): string => {
|
||||
const unquotedName = unquoteWithUnescape(name);
|
||||
// Unquoted value can be an empty string which we want to display as ""
|
||||
const unquotedValue = unquoteWithUnescape(value) || '""';
|
||||
return `${name} ${operator} ${unquotedValue}`;
|
||||
return `${unquotedName} ${operator} ${unquotedValue}`;
|
||||
},
|
||||
} as const;
|
||||
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
getInheritedProperties,
|
||||
matchLabels,
|
||||
normalizeRoute,
|
||||
unquoteRouteMatchers,
|
||||
} from './notification-policies';
|
||||
|
||||
import 'core-js/stable/structured-clone';
|
||||
@ -476,3 +477,39 @@ describe('matchLabels', () => {
|
||||
expect(result.labelsMatch).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('unquoteRouteMatchers', () => {
|
||||
it('should unquote and unescape matchers values', () => {
|
||||
const route: RouteWithID = {
|
||||
id: '1',
|
||||
object_matchers: [
|
||||
['foo', MatcherOperator.equal, 'bar'],
|
||||
['foo', MatcherOperator.equal, '"bar"'],
|
||||
['foo', MatcherOperator.equal, '"b\\\\ar b\\"az"'],
|
||||
],
|
||||
};
|
||||
|
||||
const unwrapped = unquoteRouteMatchers(route);
|
||||
|
||||
expect(unwrapped.object_matchers).toHaveLength(3);
|
||||
expect(unwrapped.object_matchers).toContainEqual(['foo', MatcherOperator.equal, 'bar']);
|
||||
expect(unwrapped.object_matchers).toContainEqual(['foo', MatcherOperator.equal, 'bar']);
|
||||
expect(unwrapped.object_matchers).toContainEqual(['foo', MatcherOperator.equal, 'b\\ar b"az']);
|
||||
});
|
||||
|
||||
it('should unquote and unescape matcher names', () => {
|
||||
const route: RouteWithID = {
|
||||
id: '1',
|
||||
object_matchers: [
|
||||
['"f\\"oo with quote"', MatcherOperator.equal, 'bar'],
|
||||
['"f\\\\oo with slash"', MatcherOperator.equal, 'bar'],
|
||||
],
|
||||
};
|
||||
|
||||
const unwrapped = unquoteRouteMatchers(route);
|
||||
|
||||
expect(unwrapped.object_matchers).toHaveLength(2);
|
||||
expect(unwrapped.object_matchers).toContainEqual(['f"oo with quote', MatcherOperator.equal, 'bar']);
|
||||
expect(unwrapped.object_matchers).toContainEqual(['f\\oo with slash', MatcherOperator.equal, 'bar']);
|
||||
});
|
||||
});
|
||||
|
@ -127,7 +127,7 @@ export function normalizeRoute(rootRoute: RouteWithID): RouteWithID {
|
||||
export function unquoteRouteMatchers(route: RouteWithID): RouteWithID {
|
||||
function unquoteRoute(route: RouteWithID) {
|
||||
route.object_matchers = route.object_matchers?.map(([name, operator, value]) => {
|
||||
return [name, operator, unquoteWithUnescape(value)];
|
||||
return [unquoteWithUnescape(name), operator, unquoteWithUnescape(value)];
|
||||
});
|
||||
route.routes?.forEach(unquoteRoute);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user