From 799461d8bf3af69319bff0aadecc07f8af6bb166 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Thu, 18 Mar 2021 16:15:27 +0200 Subject: [PATCH] app/vmselect/graphite: follow-up after 529d7be26b6fb2836856a661c4fcc54ca26731d4 --- app/vmselect/graphite/metrics_api.go | 50 ++++++++++++++++------------ docs/CHANGELOG.md | 1 + 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/app/vmselect/graphite/metrics_api.go b/app/vmselect/graphite/metrics_api.go index 6b7ff1087..465dff496 100644 --- a/app/vmselect/graphite/metrics_api.go +++ b/app/vmselect/graphite/metrics_api.go @@ -230,24 +230,33 @@ func MetricsIndexHandler(startTime time.Time, at *auth.Token, w http.ResponseWri return nil } -// metricsFind searches for label values that match the given head and tail. -func metricsFind(at *auth.Token, denyPartialResponse bool, tr storage.TimeRange, label, head, tail string, delimiter byte, +// metricsFind searches for label values that match the given qHead and qTail. +func metricsFind(at *auth.Token, denyPartialResponse bool, tr storage.TimeRange, label, qHead, qTail string, delimiter byte, isExpand bool, deadline searchutils.Deadline) ([]string, bool, error) { - n := strings.IndexAny(tail, "*{[") - // fast path. + n := strings.IndexAny(qTail, "*{[") if n < 0 { - res, isPartial, err := netstorage.GetTagValueSuffixes(at, denyPartialResponse, tr, label, head+tail, delimiter, deadline) + query := qHead + qTail + suffixes, isPartial, err := netstorage.GetTagValueSuffixes(at, denyPartialResponse, tr, label, query, delimiter, deadline) if err != nil { return nil, false, err } - if len(res) == 0 { + if len(suffixes) == 0 { return nil, false, nil } - return []string{head + tail}, isPartial, nil + if len(query) > 0 && query[len(query)-1] == delimiter { + return []string{query}, isPartial, nil + } + results := make([]string, 0, len(suffixes)) + for _, suffix := range suffixes { + if len(suffix) == 0 || len(suffix) == 1 && suffix[0] == delimiter { + results = append(results, query+suffix) + } + } + return results, isPartial, nil } - if strings.HasSuffix(head, "*") { - head = head[:len(head)-1] - suffixes, isPartial, err := netstorage.GetTagValueSuffixes(at, denyPartialResponse, tr, label, head, delimiter, deadline) + if n == len(qTail)-1 && strings.HasSuffix(qTail, "*") { + query := qHead + qTail[:len(qTail)-1] + suffixes, isPartial, err := netstorage.GetTagValueSuffixes(at, denyPartialResponse, tr, label, query, delimiter, deadline) if err != nil { return nil, false, err } @@ -256,25 +265,22 @@ func metricsFind(at *auth.Token, denyPartialResponse bool, tr storage.TimeRange, } results := make([]string, 0, len(suffixes)) for _, suffix := range suffixes { - results = append(results, head+suffix) + results = append(results, query+suffix) } return results, isPartial, nil } - - head += tail[:n] - subquery := head + "*" - // execute subquery with the given head. - paths, isPartial, err := metricsFind(at, denyPartialResponse, tr, label, subquery, "*", delimiter, isExpand, deadline) + qHead += qTail[:n] + paths, isPartial, err := metricsFind(at, denyPartialResponse, tr, label, qHead, "*", delimiter, isExpand, deadline) if err != nil { return nil, false, err } - tailNew := "" - suffix := tail[n:] + suffix := qTail[n:] + qTail = "" if m := strings.IndexByte(suffix, delimiter); m >= 0 { - tailNew = suffix[m+1:] + qTail = suffix[m+1:] suffix = suffix[:m+1] } - qPrefix := head + suffix + qPrefix := qHead + suffix rePrefix, err := getRegexpForQuery(qPrefix, delimiter) if err != nil { return nil, false, fmt.Errorf("cannot convert query %q to regexp: %w", qPrefix, err) @@ -284,11 +290,11 @@ func metricsFind(at *auth.Token, denyPartialResponse bool, tr storage.TimeRange, if !rePrefix.MatchString(path) { continue } - if tailNew == "" { + if qTail == "" { results = append(results, path) continue } - fullPaths, isPartialLocal, err := metricsFind(at, denyPartialResponse, tr, label, path, tailNew, delimiter, isExpand, deadline) + fullPaths, isPartialLocal, err := metricsFind(at, denyPartialResponse, tr, label, path, qTail, delimiter, isExpand, deadline) if err != nil { return nil, false, err } diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 89f1f05df..c646f3f60 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -10,6 +10,7 @@ * `process_virtual_memory_peak_bytes` - peak virtual memory usage for the process. * BUGFIX: prevent from infinite loop on `{__graphite__="..."}` filters when a metric name contains `*`, `{` or `[` chars. +* BUGFIX: prevent from infinite loop in `/metrics/find` and `/metrics/expand` [Graphite Metrics API handlers](https://victoriametrics.github.io/#graphite-metrics-api-usage) when they match metric names or labels with `*`, `{` or `[` chars. # [v1.56.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.56.0)