diff --git a/pkg/promclient/label.go b/pkg/promclient/label.go index abc394794..3b650464a 100644 --- a/pkg/promclient/label.go +++ b/pkg/promclient/label.go @@ -59,24 +59,31 @@ func (c *AddLabelClient) Key() model.LabelSet { func (c *AddLabelClient) filterMatchers(matchers []string) ([]string, bool, error) { ret := make([]string, 0, len(matchers)) - for i, matcher := range matchers { + for _, matcher := range matchers { selectors, err := parser.ParseMetricSelector(matcher) if err != nil { return nil, true, err } + filteredSelectors := make([]*labels.Matcher, 0, len(selectors)) + // If the selector matches our value -- remove the selector // if the selector doesn't match, return empty - for sI, s := range selectors { + for _, s := range selectors { if v, ok := c.Labels[model.LabelName(s.Name)]; ok { - if s.Matches(string(v)) { - selectors = append(selectors[:sI], selectors[i+1:]...) - } else { + // If the selector doesn't match the labels from our client; we don't match + if !s.Matches(string(v)) { return nil, false, nil } + } else { // Otherwise if the selector isn't part of the `Labels` we add; we pass it along + filteredSelectors = append(filteredSelectors, s) } } - newMatcher, err := promhttputil.MatcherToString(selectors) + // If the selector is cleared -- then we skip it in the return + if len(filteredSelectors) == 0 { + continue + } + newMatcher, err := promhttputil.MatcherToString(filteredSelectors) if err != nil { return nil, false, err } @@ -87,6 +94,14 @@ func (c *AddLabelClient) filterMatchers(matchers []string) ([]string, bool, erro // LabelNames returns all the unique label names present in the block in sorted order. func (c *AddLabelClient) LabelNames(ctx context.Context, matchers []string, startTime time.Time, endTime time.Time) ([]string, v1.Warnings, error) { + matchers, ok, err := c.filterMatchers(matchers) + if err != nil { + return nil, nil, err + } + if !ok { + return nil, nil, nil + } + l, w, err := c.API.LabelNames(ctx, matchers, startTime, endTime) if err != nil { return nil, nil, err diff --git a/pkg/promclient/label_test.go b/pkg/promclient/label_test.go index 9f97ff11a..6e3cd34a6 100644 --- a/pkg/promclient/label_test.go +++ b/pkg/promclient/label_test.go @@ -98,7 +98,36 @@ type labelStubAPI struct { } func (a *labelStubAPI) LabelNames(ctx context.Context, matchers []string, startTime time.Time, endTime time.Time) ([]string, v1.Warnings, error) { - return nil, nil, fmt.Errorf("not implemented") + series := append([]model.LabelSet{}, a.series...) + for _, m := range matchers { + selectors, err := parser.ParseMetricSelector(m) + if err != nil { + return nil, nil, err + } + for _, selector := range selectors { + for i, s := range series { + v, ok := s[model.LabelName(selector.Name)] + if !ok || !selector.Matches(string(v)) { + series = append(series[:i], series[i+1:]...) + } + } + } + } + + names := make(map[string]struct{}) + for _, s := range series { + for k := range s { + if strings.HasPrefix(string(k), model.ReservedLabelPrefix) { + continue + } + names[string(k)] = struct{}{} + } + } + ret := make([]string, 0, len(names)) + for k := range names { + ret = append(ret, k) + } + return ret, nil, nil } func (a *labelStubAPI) LabelValues(ctx context.Context, label string, matchers []string, startTime time.Time, endTime time.Time) (model.LabelValues, v1.Warnings, error) { @@ -171,16 +200,37 @@ func TestAddLabelClient(t *testing.T) { err bool matchers []string labelValues []string + labelNames []string }{ { labelSet: model.LabelSet{"b": "1"}, labelValues: []string{"1"}, + labelNames: []string{"a", "b"}, }, { labelSet: model.LabelSet{"b": "1"}, labelValues: []string{"1"}, + labelNames: []string{"a", "b"}, matchers: []string{`{b="1"}`}, }, + { + labelSet: model.LabelSet{"b": "1", "c": "1"}, + labelValues: []string{"1"}, + labelNames: []string{"a", "b", "c"}, + matchers: []string{`{b="1", c="1"}`}, + }, + { + labelSet: model.LabelSet{"b": "1", "c": "1", "d": "1"}, + labelValues: []string{"1"}, + labelNames: []string{"a", "b", "c", "d"}, + matchers: []string{`{b="1", c="1"}`}, + }, + { + labelSet: model.LabelSet{"b": "1", "c": "1", "d": "1"}, + labelValues: []string{"1"}, + labelNames: []string{"a", "b", "c", "d"}, + matchers: []string{`{a="1", b="1", c="1"}`}, + }, } for i, test := range tests { @@ -207,6 +257,29 @@ func TestAddLabelClient(t *testing.T) { } } }) + + t.Run("LabelValues", func(t *testing.T) { + v, _, err := a.LabelNames(context.TODO(), test.matchers, time.Time{}, time.Time{}) + if err != nil != test.err { + if test.err { + t.Fatalf("missing expected err") + } else { + t.Fatalf("Unexpected Err: %v", err) + } + } + if err == nil { + if len(v) != len(test.labelNames) { + t.Fatalf("mismatch in len: \nexpected=%v\nactual=%v", test.labelNames, v) + } + + for i, actualV := range v { + if actualV != test.labelNames[i] { + t.Fatalf("mismatch in value: \nexpected=%v\nactual=%v", test.labelNames, v) + } + } + } + }) + }) } }