Merge pull request #11074 from damnever/fix/datamodelvalidation

Validate the metric name and label names
This commit is contained in:
Julien Pivotto 2022-12-08 14:31:12 +01:00 committed by GitHub
commit bb323db613
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 119 additions and 0 deletions

View file

@ -20,6 +20,7 @@ import (
"strconv"
"github.com/cespare/xxhash/v2"
"github.com/prometheus/common/model"
)
// Well-known label names used by Prometheus components.
@ -312,6 +313,19 @@ func (ls Labels) WithoutEmpty() Labels {
return ls
}
// IsValid checks if the metric name or label names are valid.
func (ls Labels) IsValid() bool {
for _, l := range ls {
if l.Name == model.MetricNameLabel && !model.IsValidMetricName(model.LabelValue(l.Value)) {
return false
}
if !model.LabelName(l.Name).IsValid() || !model.LabelValue(l.Value).IsValid() {
return false
}
}
return true
}
// Equal returns whether the two label sets are equal.
func Equal(ls, o Labels) bool {
if len(ls) != len(o) {

View file

@ -216,6 +216,62 @@ func TestLabels_WithoutEmpty(t *testing.T) {
}
}
func TestLabels_IsValid(t *testing.T) {
for _, test := range []struct {
input Labels
expected bool
}{
{
input: FromStrings(
"__name__", "test",
"hostname", "localhost",
"job", "check",
),
expected: true,
},
{
input: FromStrings(
"__name__", "test:ms",
"hostname_123", "localhost",
"_job", "check",
),
expected: true,
},
{
input: FromStrings("__name__", "test-ms"),
expected: false,
},
{
input: FromStrings("__name__", "0zz"),
expected: false,
},
{
input: FromStrings("abc:xyz", "invalid"),
expected: false,
},
{
input: FromStrings("123abc", "invalid"),
expected: false,
},
{
input: FromStrings("中文abc", "invalid"),
expected: false,
},
{
input: FromStrings("invalid", "aa\xe2"),
expected: false,
},
{
input: FromStrings("invalid", "\xF7\xBF\xBF\xBF"),
expected: false,
},
} {
t.Run("", func(t *testing.T) {
require.Equal(t, test.expected, test.input.IsValid())
})
}
}
func TestLabels_Equal(t *testing.T) {
labels := FromStrings(
"aaa", "111",

View file

@ -1609,6 +1609,10 @@ loop:
err = errNameLabelMandatory
break loop
}
if !lset.IsValid() {
err = fmt.Errorf("invalid metric name or label names: %s", lset.String())
break loop
}
// If any label limits is exceeded the scrape should fail.
if err = verifyLabelLimits(lset, sl.labelLimits); err != nil {

View file

@ -1020,6 +1020,51 @@ func TestScrapeLoopSeriesAdded(t *testing.T) {
require.Equal(t, 0, seriesAdded)
}
func TestScrapeLoopFailWithInvalidLabelsAfterRelabel(t *testing.T) {
s := teststorage.New(t)
defer s.Close()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
target := &Target{
labels: labels.FromStrings("pod_label_invalid_012", "test"),
}
relabelConfig := []*relabel.Config{{
Action: relabel.LabelMap,
Regex: relabel.MustNewRegexp("pod_label_invalid_(.+)"),
Separator: ";",
Replacement: "$1",
}}
sl := newScrapeLoop(ctx,
&testScraper{},
nil, nil,
func(l labels.Labels) labels.Labels {
return mutateSampleLabels(l, target, true, relabelConfig)
},
nopMutator,
s.Appender,
nil,
0,
true,
0,
nil,
0,
0,
false,
false,
nil,
false,
)
slApp := sl.appender(ctx)
total, added, seriesAdded, err := sl.append(slApp, []byte("test_metric 1\n"), "", time.Time{})
require.ErrorContains(t, err, "invalid metric name or label names")
require.NoError(t, slApp.Rollback())
require.Equal(t, 1, total)
require.Equal(t, 0, added)
require.Equal(t, 0, seriesAdded)
}
func makeTestMetrics(n int) []byte {
// Construct a metrics string to parse
sb := bytes.Buffer{}