prometheus: query field: better handle label-values with unusual characters (#41457)

This commit is contained in:
Gábor Farkas 2021-11-15 09:51:28 +01:00 committed by GitHub
parent 16578b0af0
commit 5c40865547
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 7 deletions

View File

@ -2,6 +2,7 @@ import type { Situation, Label } from './situation';
import { NeverCaseError } from './util';
// FIXME: we should not load this from the "outside", but we cannot do that while we have the "old" query-field too
import { FUNCTIONS } from '../../../promql';
import { escapeLabelValueInExactSelector } from '../../../language_utils';
export type CompletionType = 'HISTORY' | 'FUNCTION' | 'METRIC_NAME' | 'DURATION' | 'LABEL_NAME' | 'LABEL_VALUE';
@ -90,7 +91,9 @@ function makeSelector(metricName: string | undefined, labels: Label[]): string {
allLabels.push({ name: '__name__', value: metricName, op: '=' });
}
const allLabelTexts = allLabels.map((label) => `${label.name}${label.op}"${label.value}"`);
const allLabelTexts = allLabels.map(
(label) => `${label.name}${label.op}"${escapeLabelValueInExactSelector(label.value)}"`
);
return `{${allLabelTexts.join(',')}}`;
}

View File

@ -89,6 +89,24 @@ describe('situation', () => {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
otherLabels: [{ name: 'one', value: 'val1', op: '=' }],
});
// single-quoted label-values with escape
assertSituation("{one='val\\'1',^}", {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
otherLabels: [{ name: 'one', value: "val'1", op: '=' }],
});
// double-quoted label-values with escape
assertSituation('{one="val\\"1",^}', {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
otherLabels: [{ name: 'one', value: 'val"1', op: '=' }],
});
// backticked label-values with escape (the escape should not be interpreted)
assertSituation('{one=`val\\"1`,^}', {
type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME',
otherLabels: [{ name: 'one', value: 'val\\"1', op: '=' }],
});
});
it('handles label values', () => {

View File

@ -63,17 +63,34 @@ function getNodeText(node: SyntaxNode, text: string): string {
}
function parsePromQLStringLiteral(text: string): string {
// if it is a string-literal, it is inside quotes of some kind
const inside = text.slice(1, text.length - 1);
// FIXME: support https://prometheus.io/docs/prometheus/latest/querying/basics/#string-literals
// FIXME: maybe check other promql code, if all is supported or not
// for now we do only some very simple un-escaping
// we start with double-quotes
if (text.startsWith('"') && text.endsWith('"')) {
if (text.indexOf('\\') !== -1) {
throw new Error('FIXME: escape-sequences not supported in label-values');
}
return text.slice(1, text.length - 1);
} else {
throw new Error('FIXME: invalid string literal');
// NOTE: this is not 100% perfect, we only unescape the double-quote,
// there might be other characters too
return inside.replace(/\\"/, '"');
}
// then single-quote
if (text.startsWith("'") && text.endsWith("'")) {
// NOTE: this is not 100% perfect, we only unescape the single-quote,
// there might be other characters too
return inside.replace(/\\'/, "'");
}
// then backticks
if (text.startsWith('`') && text.endsWith('`')) {
return inside;
}
throw new Error('FIXME: invalid string literal');
}
type LabelOperator = '=' | '!=' | '=~' | '!~';