From 91d8a5c5657e7d82a2d741b3618e7fbe41cb7164 Mon Sep 17 00:00:00 2001 From: Ben Ye Date: Thu, 30 Jul 2020 22:34:46 -0400 Subject: [PATCH] add time range parameters to labels API Signed-off-by: Ben Ye --- .bingo/Variables.mk | 6 +- .bingo/prometheus.1.mod | 8 +- .bingo/variables.env | 2 +- CHANGELOG.md | 1 + pkg/api/query/v1.go | 82 ++++++---- pkg/promclient/promclient.go | 14 +- pkg/query/querier.go | 13 +- pkg/store/bucket.go | 8 +- pkg/store/bucket_e2e_test.go | 74 ++++++++- pkg/store/prometheus.go | 6 +- pkg/store/prometheus_test.go | 26 +++- pkg/store/proxy.go | 4 + pkg/store/proxy_test.go | 9 ++ pkg/store/storepb/rpc.pb.go | 238 +++++++++++++++++++++-------- pkg/store/storepb/rpc.proto | 8 + pkg/store/tsdb.go | 6 +- pkg/store/tsdb_test.go | 113 +++++++++++++- pkg/testutil/e2eutil/prometheus.go | 2 +- test/e2e/e2ethanos/services.go | 2 +- test/e2e/query_test.go | 125 +++++++++++++++ 20 files changed, 623 insertions(+), 124 deletions(-) diff --git a/.bingo/Variables.mk b/.bingo/Variables.mk index 8ba8db120a2..4659f2341ab 100644 --- a/.bingo/Variables.mk +++ b/.bingo/Variables.mk @@ -100,13 +100,13 @@ $(MINIO): .bingo/minio.mod @echo "(re)installing $(GOBIN)/minio-v0.0.0-20200527010300-cccf2de129da" @cd .bingo && $(GO) build -modfile=minio.mod -o=$(GOBIN)/minio-v0.0.0-20200527010300-cccf2de129da "github.com/minio/minio" -PROMETHEUS_ARRAY := $(GOBIN)/prometheus-v2.4.3+incompatible $(GOBIN)/prometheus-v1.8.2-0.20200507164740-ecee9c8abfd1 +PROMETHEUS_ARRAY := $(GOBIN)/prometheus-v2.4.3+incompatible $(GOBIN)/prometheus-v1.8.2-0.20200724121523-657ba532e42f $(PROMETHEUS_ARRAY): .bingo/prometheus.mod .bingo/prometheus.1.mod @# Install binary/ries using Go 1.14+ build command. This is using bwplotka/bingo-controlled, separate go module with pinned dependencies. @echo "(re)installing $(GOBIN)/prometheus-v2.4.3+incompatible" @cd .bingo && $(GO) build -modfile=prometheus.mod -o=$(GOBIN)/prometheus-v2.4.3+incompatible "github.com/prometheus/prometheus/cmd/prometheus" - @echo "(re)installing $(GOBIN)/prometheus-v1.8.2-0.20200507164740-ecee9c8abfd1" - @cd .bingo && $(GO) build -modfile=prometheus.1.mod -o=$(GOBIN)/prometheus-v1.8.2-0.20200507164740-ecee9c8abfd1 "github.com/prometheus/prometheus/cmd/prometheus" + @echo "(re)installing $(GOBIN)/prometheus-v1.8.2-0.20200724121523-657ba532e42f" + @cd .bingo && $(GO) build -modfile=prometheus.1.mod -o=$(GOBIN)/prometheus-v1.8.2-0.20200724121523-657ba532e42f "github.com/prometheus/prometheus/cmd/prometheus" PROMTOOL := $(GOBIN)/promtool-v1.8.2-0.20200522113006-f4dd45609a05 $(PROMTOOL): .bingo/promtool.mod diff --git a/.bingo/prometheus.1.mod b/.bingo/prometheus.1.mod index 5816163b508..ce88bcc6dd6 100644 --- a/.bingo/prometheus.1.mod +++ b/.bingo/prometheus.1.mod @@ -2,14 +2,14 @@ module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT go 1.14 -require github.com/prometheus/prometheus v1.8.2-0.20200507164740-ecee9c8abfd1 // cmd/prometheus +require github.com/prometheus/prometheus v1.8.2-0.20200724121523-657ba532e42f // cmd/prometheus replace ( // Mitigation for: https://github.com/Azure/go-autorest/issues/414 github.com/Azure/go-autorest => github.com/Azure/go-autorest v12.3.0+incompatible - k8s.io/api => k8s.io/api v0.17.5 - k8s.io/apimachinery => k8s.io/apimachinery v0.17.5 - k8s.io/client-go => k8s.io/client-go v0.17.5 + k8s.io/api => k8s.io/api v0.18.6 + k8s.io/apimachinery => k8s.io/apimachinery v0.18.6 + k8s.io/client-go => k8s.io/client-go v0.18.6 k8s.io/klog => github.com/simonpasquier/klog-gokit v0.1.0 k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30 ) diff --git a/.bingo/variables.env b/.bingo/variables.env index 2b8403a4f70..ebb3455ee37 100644 --- a/.bingo/variables.env +++ b/.bingo/variables.env @@ -36,7 +36,7 @@ LICHE="${gobin}/liche-v0.0.0-20181124191719-2a2e6e56f6c6" MINIO="${gobin}/minio-v0.0.0-20200527010300-cccf2de129da" -PROMETHEUS_ARRAY="${gobin}/prometheus-v2.4.3+incompatible${gobin}/prometheus-v1.8.2-0.20200507164740-ecee9c8abfd1" +PROMETHEUS_ARRAY="${gobin}/prometheus-v2.4.3+incompatible${gobin}/prometheus-v1.8.2-0.20200724121523-657ba532e42f" PROMTOOL="${gobin}/promtool-v1.8.2-0.20200522113006-f4dd45609a05" diff --git a/CHANGELOG.md b/CHANGELOG.md index ef6a552bfdc..2abeb74484a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ We use *breaking* word for marking changes that are not backward compatible (rel - [#2926](https://github.com/thanos-io/thanos/pull/2926) API: Add new blocks HTTP API to serve blocks metadata. The status endpoints (`/api/v1/status/flags`, `/api/v1/status/runtimeinfo` and `/api/v1/status/buildinfo`) are now available on all components with a HTTP API. - [#2892](https://github.com/thanos-io/thanos/pull/2892) Receive: Receiver fails when the initial upload fails. - [#2865](https://github.com/thanos-io/thanos/pull/2865) ui: Migrate Thanos Ruler UI to React +- [#2964](https://github.com/thanos-io/thanos/pull/2964) Query: Add time range parameters to label APIs. Add `start` and `end` fields to Store API `LabelNamesRequest` and `LabelValuesRequest`. ### Changed diff --git a/pkg/api/query/v1.go b/pkg/api/query/v1.go index 5d6a10a1e12..27aad021a72 100644 --- a/pkg/api/query/v1.go +++ b/pkg/api/query/v1.go @@ -203,15 +203,9 @@ func (qapi *QueryAPI) parsePartialResponseParam(r *http.Request, defaultEnablePa } func (qapi *QueryAPI) query(r *http.Request) (interface{}, []error, *api.ApiError) { - var ts time.Time - if t := r.FormValue("time"); t != "" { - var err error - ts, err = parseTime(t) - if err != nil { - return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err} - } - } else { - ts = qapi.baseAPI.Now() + ts, err := parseTimeParam(r, "time", qapi.baseAPI.Now()) + if err != nil { + return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err} } ctx := r.Context() @@ -394,12 +388,27 @@ func (qapi *QueryAPI) labelValues(r *http.Request) (interface{}, []error, *api.A return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("invalid label name: %q", name)} } + start, err := parseTimeParam(r, "start", minTime) + if err != nil { + return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err} + } + end, err := parseTimeParam(r, "end", maxTime) + if err != nil { + return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err} + } + // Prometheus doesn't check this, do we need to? + if end.Before(start) { + err := errors.New("end timestamp must not be before start time") + return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err} + } + enablePartialResponse, apiErr := qapi.parsePartialResponseParam(r, qapi.enableQueryPartialResponse) if apiErr != nil { return nil, nil, apiErr } - q, err := qapi.queryableCreate(true, nil, 0, enablePartialResponse, false).Querier(ctx, math.MinInt64, math.MaxInt64) + q, err := qapi.queryableCreate(true, nil, 0, enablePartialResponse, false). + Querier(ctx, timestamp.FromTime(start), timestamp.FromTime(end)) if err != nil { return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: err} } @@ -433,26 +442,13 @@ func (qapi *QueryAPI) series(r *http.Request) (interface{}, []error, *api.ApiErr return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.New("no match[] parameter provided")} } - var start time.Time - if t := r.FormValue("start"); t != "" { - var err error - start, err = parseTime(t) - if err != nil { - return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err} - } - } else { - start = minTime + start, err := parseTimeParam(r, "start", minTime) + if err != nil { + return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err} } - - var end time.Time - if t := r.FormValue("end"); t != "" { - var err error - end, err = parseTime(t) - if err != nil { - return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err} - } - } else { - end = maxTime + end, err := parseTimeParam(r, "end", maxTime) + if err != nil { + return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err} } var matcherSets [][]*labels.Matcher @@ -504,6 +500,18 @@ func (qapi *QueryAPI) series(r *http.Request) (interface{}, []error, *api.ApiErr return metrics, set.Warnings(), nil } +func parseTimeParam(r *http.Request, paramName string, defaultValue time.Time) (time.Time, error) { + val := r.FormValue(paramName) + if val == "" { + return defaultValue, nil + } + result, err := parseTime(val) + if err != nil { + return time.Time{}, errors.Wrapf(err, "Invalid time value for '%s'", paramName) + } + return result, nil +} + func parseTime(s string) (time.Time, error) { if t, err := strconv.ParseFloat(s, 64); err == nil { s, ns := math.Modf(t) @@ -532,12 +540,26 @@ func parseDuration(s string) (time.Duration, error) { func (qapi *QueryAPI) labelNames(r *http.Request) (interface{}, []error, *api.ApiError) { ctx := r.Context() + start, err := parseTimeParam(r, "start", minTime) + if err != nil { + return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err} + } + end, err := parseTimeParam(r, "end", maxTime) + if err != nil { + return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err} + } + if end.Before(start) { + err := errors.New("end timestamp must not be before start time") + return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err} + } + enablePartialResponse, apiErr := qapi.parsePartialResponseParam(r, qapi.enableQueryPartialResponse) if apiErr != nil { return nil, nil, apiErr } - q, err := qapi.queryableCreate(true, nil, 0, enablePartialResponse, false).Querier(ctx, math.MinInt64, math.MaxInt64) + q, err := qapi.queryableCreate(true, nil, 0, enablePartialResponse, false). + Querier(ctx, timestamp.FromTime(start), timestamp.FromTime(end)) if err != nil { return nil, nil, &api.ApiError{Typ: api.ErrorExec, Err: err} } diff --git a/pkg/promclient/promclient.go b/pkg/promclient/promclient.go index 2cdbc7124a1..ac495d619b7 100644 --- a/pkg/promclient/promclient.go +++ b/pkg/promclient/promclient.go @@ -587,9 +587,14 @@ func (c *Client) SeriesInGRPC(ctx context.Context, base *url.URL, matchers []sto // LabelNames returns all known label names. It uses gRPC errors. // NOTE: This method is tested in pkg/store/prometheus_test.go against Prometheus. -func (c *Client) LabelNamesInGRPC(ctx context.Context, base *url.URL) ([]string, error) { +func (c *Client) LabelNamesInGRPC(ctx context.Context, base *url.URL, startTime, endTime int64) ([]string, error) { u := *base u.Path = path.Join(u.Path, "/api/v1/labels") + q := u.Query() + + q.Add("start", formatTime(timestamp.Time(startTime))) + q.Add("end", formatTime(timestamp.Time(endTime))) + u.RawQuery = q.Encode() var m struct { Data []string `json:"data"` @@ -599,9 +604,14 @@ func (c *Client) LabelNamesInGRPC(ctx context.Context, base *url.URL) ([]string, // LabelValuesInGRPC returns all known label values for a given label name. It uses gRPC errors. // NOTE: This method is tested in pkg/store/prometheus_test.go against Prometheus. -func (c *Client) LabelValuesInGRPC(ctx context.Context, base *url.URL, label string) ([]string, error) { +func (c *Client) LabelValuesInGRPC(ctx context.Context, base *url.URL, label string, startTime, endTime int64) ([]string, error) { u := *base u.Path = path.Join(u.Path, "/api/v1/label/", label, "/values") + q := u.Query() + + q.Add("start", formatTime(timestamp.Time(startTime))) + q.Add("end", formatTime(timestamp.Time(endTime))) + u.RawQuery = q.Encode() var m struct { Data []string `json:"data"` diff --git a/pkg/query/querier.go b/pkg/query/querier.go index 1fcd4f1a72f..f78d021163a 100644 --- a/pkg/query/querier.go +++ b/pkg/query/querier.go @@ -324,7 +324,12 @@ func (q *querier) LabelValues(name string) ([]string, storage.Warnings, error) { span, ctx := tracing.StartSpan(q.ctx, "querier_label_values") defer span.Finish() - resp, err := q.proxy.LabelValues(ctx, &storepb.LabelValuesRequest{Label: name, PartialResponseDisabled: !q.partialResponse}) + resp, err := q.proxy.LabelValues(ctx, &storepb.LabelValuesRequest{ + Label: name, + PartialResponseDisabled: !q.partialResponse, + Start: q.mint, + End: q.maxt, + }) if err != nil { return nil, nil, errors.Wrap(err, "proxy LabelValues()") } @@ -342,7 +347,11 @@ func (q *querier) LabelNames() ([]string, storage.Warnings, error) { span, ctx := tracing.StartSpan(q.ctx, "querier_label_names") defer span.Finish() - resp, err := q.proxy.LabelNames(ctx, &storepb.LabelNamesRequest{PartialResponseDisabled: !q.partialResponse}) + resp, err := q.proxy.LabelNames(ctx, &storepb.LabelNamesRequest{ + PartialResponseDisabled: !q.partialResponse, + Start: q.mint, + End: q.maxt, + }) if err != nil { return nil, nil, errors.Wrap(err, "proxy LabelNames()") } diff --git a/pkg/store/bucket.go b/pkg/store/bucket.go index f511149b0be..2a609ae1908 100644 --- a/pkg/store/bucket.go +++ b/pkg/store/bucket.go @@ -1046,7 +1046,7 @@ func chunksSize(chks []storepb.AggrChunk) (size int) { } // LabelNames implements the storepb.StoreServer interface. -func (s *BucketStore) LabelNames(ctx context.Context, _ *storepb.LabelNamesRequest) (*storepb.LabelNamesResponse, error) { +func (s *BucketStore) LabelNames(ctx context.Context, r *storepb.LabelNamesRequest) (*storepb.LabelNamesResponse, error) { g, gctx := errgroup.WithContext(ctx) s.mtx.RLock() @@ -1055,6 +1055,9 @@ func (s *BucketStore) LabelNames(ctx context.Context, _ *storepb.LabelNamesReque var sets [][]string for _, b := range s.blocks { + if b.meta.MinTime > r.End || b.meta.MaxTime < r.Start { + continue + } indexr := b.indexReader(gctx) g.Go(func() error { defer runutil.CloseWithLogOnErr(s.logger, indexr, "label names") @@ -1091,6 +1094,9 @@ func (s *BucketStore) LabelValues(ctx context.Context, req *storepb.LabelValuesR var sets [][]string for _, b := range s.blocks { + if b.meta.MinTime > req.End || b.meta.MaxTime < req.Start { + continue + } indexr := b.indexReader(gctx) g.Go(func() error { defer runutil.CloseWithLogOnErr(s.logger, indexr, "label values") diff --git a/pkg/store/bucket_e2e_test.go b/pkg/store/bucket_e2e_test.go index f7847619fa4..831d5280760 100644 --- a/pkg/store/bucket_e2e_test.go +++ b/pkg/store/bucket_e2e_test.go @@ -191,7 +191,11 @@ func testBucketStore_e2e(t *testing.T, ctx context.Context, s *storeSuite) { testutil.Equals(t, s.minTime, mint) testutil.Equals(t, s.maxTime, maxt) - vals, err := s.store.LabelValues(ctx, &storepb.LabelValuesRequest{Label: "a"}) + vals, err := s.store.LabelValues(ctx, &storepb.LabelValuesRequest{ + Label: "a", + Start: timestamp.FromTime(minTime), + End: timestamp.FromTime(maxTime), + }) testutil.Ok(t, err) testutil.Equals(t, []string{"1", "2"}, vals.Values) @@ -381,7 +385,7 @@ func testBucketStore_e2e(t *testing.T, ctx context.Context, s *storeSuite) { MaxTime: maxt, }, }, - // Test no-chunk option. + // Test skip-chunk option. { req: &storepb.SeriesRequest{ Matchers: []storepb.LabelMatcher{ @@ -599,3 +603,69 @@ func TestBucketStore_Series_ChunksLimiter_e2e(t *testing.T) { }) } } + +func TestBucketStore_LabelNames_e2e(t *testing.T) { + objtesting.ForeachStore(t, func(t *testing.T, bkt objstore.Bucket) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + dir, err := ioutil.TempDir("", "test_bucketstore_label_names_e2e") + testutil.Ok(t, err) + defer func() { testutil.Ok(t, os.RemoveAll(dir)) }() + + s := prepareStoreWithTestBlocks(t, dir, bkt, false, 0, emptyRelabelConfig, allowAllFilterConf) + + mint, maxt := s.store.TimeRange() + testutil.Equals(t, s.minTime, mint) + testutil.Equals(t, s.maxTime, maxt) + + vals, err := s.store.LabelNames(ctx, &storepb.LabelNamesRequest{ + Start: timestamp.FromTime(minTime), + End: timestamp.FromTime(maxTime), + }) + testutil.Ok(t, err) + testutil.Equals(t, []string{"a", "b", "c"}, vals.Names) + + // Outside the time range. + vals, err = s.store.LabelNames(ctx, &storepb.LabelNamesRequest{ + Start: timestamp.FromTime(time.Now().Add(-24 * time.Hour)), + End: timestamp.FromTime(time.Now().Add(-23 * time.Hour)), + }) + testutil.Ok(t, err) + testutil.Equals(t, []string(nil), vals.Names) + }) +} + +func TestBucketStore_LabelValues_e2e(t *testing.T) { + objtesting.ForeachStore(t, func(t *testing.T, bkt objstore.Bucket) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + dir, err := ioutil.TempDir("", "test_bucketstore_label_values_e2e") + testutil.Ok(t, err) + defer func() { testutil.Ok(t, os.RemoveAll(dir)) }() + + s := prepareStoreWithTestBlocks(t, dir, bkt, false, 0, emptyRelabelConfig, allowAllFilterConf) + + mint, maxt := s.store.TimeRange() + testutil.Equals(t, s.minTime, mint) + testutil.Equals(t, s.maxTime, maxt) + + vals, err := s.store.LabelValues(ctx, &storepb.LabelValuesRequest{ + Label: "a", + Start: timestamp.FromTime(minTime), + End: timestamp.FromTime(maxTime), + }) + testutil.Ok(t, err) + testutil.Equals(t, []string{"1", "2"}, vals.Values) + + // Outside the time range. + vals, err = s.store.LabelValues(ctx, &storepb.LabelValuesRequest{ + Label: "a", + Start: timestamp.FromTime(time.Now().Add(-24 * time.Hour)), + End: timestamp.FromTime(time.Now().Add(-23 * time.Hour)), + }) + testutil.Ok(t, err) + testutil.Equals(t, []string(nil), vals.Values) + }) +} diff --git a/pkg/store/prometheus.go b/pkg/store/prometheus.go index 83c7f8120fd..e937a40192b 100644 --- a/pkg/store/prometheus.go +++ b/pkg/store/prometheus.go @@ -519,8 +519,8 @@ Outer: } // LabelNames returns all known label names. -func (p *PrometheusStore) LabelNames(ctx context.Context, _ *storepb.LabelNamesRequest) (*storepb.LabelNamesResponse, error) { - lbls, err := p.client.LabelNamesInGRPC(ctx, p.base) +func (p *PrometheusStore) LabelNames(ctx context.Context, r *storepb.LabelNamesRequest) (*storepb.LabelNamesResponse, error) { + lbls, err := p.client.LabelNamesInGRPC(ctx, p.base, r.Start, r.End) if err != nil { return nil, err } @@ -536,7 +536,7 @@ func (p *PrometheusStore) LabelValues(ctx context.Context, r *storepb.LabelValue return &storepb.LabelValuesResponse{Values: []string{l}}, nil } - vals, err := p.client.LabelValuesInGRPC(ctx, p.base, r.Label) + vals, err := p.client.LabelValuesInGRPC(ctx, p.base, r.Label, r.Start, r.End) if err != nil { return nil, err } diff --git a/pkg/store/prometheus_test.go b/pkg/store/prometheus_test.go index 6dc9d8764a7..d8ee68ce024 100644 --- a/pkg/store/prometheus_test.go +++ b/pkg/store/prometheus_test.go @@ -378,10 +378,22 @@ func TestPrometheusStore_LabelNames_e2e(t *testing.T) { proxy, err := NewPrometheusStore(nil, promclient.NewDefaultClient(), u, component.Sidecar, getExternalLabels, nil) testutil.Ok(t, err) - resp, err := proxy.LabelNames(ctx, &storepb.LabelNamesRequest{}) + resp, err := proxy.LabelNames(ctx, &storepb.LabelNamesRequest{ + Start: timestamp.FromTime(minTime), + End: timestamp.FromTime(maxTime), + }) testutil.Ok(t, err) testutil.Equals(t, []string(nil), resp.Warnings) testutil.Equals(t, []string{"a"}, resp.Names) + + // Outside time range. + resp, err = proxy.LabelNames(ctx, &storepb.LabelNamesRequest{ + Start: timestamp.FromTime(maxTime.Add(-time.Second)), + End: timestamp.FromTime(maxTime), + }) + testutil.Ok(t, err) + testutil.Equals(t, []string(nil), resp.Warnings) + testutil.Equals(t, []string{}, resp.Names) } func TestPrometheusStore_LabelValues_e2e(t *testing.T) { @@ -413,10 +425,22 @@ func TestPrometheusStore_LabelValues_e2e(t *testing.T) { resp, err := proxy.LabelValues(ctx, &storepb.LabelValuesRequest{ Label: "a", + Start: timestamp.FromTime(minTime), + End: timestamp.FromTime(maxTime), }) testutil.Ok(t, err) testutil.Equals(t, []string(nil), resp.Warnings) testutil.Equals(t, []string{"a", "b", "c"}, resp.Values) + + // Outside time range. + resp, err = proxy.LabelValues(ctx, &storepb.LabelValuesRequest{ + Label: "a", + Start: timestamp.FromTime(maxTime.Add(-time.Second)), + End: timestamp.FromTime(maxTime), + }) + testutil.Ok(t, err) + testutil.Equals(t, []string(nil), resp.Warnings) + testutil.Equals(t, []string{}, resp.Values) } // Test to check external label values retrieve. diff --git a/pkg/store/proxy.go b/pkg/store/proxy.go index 67ae5a908f1..71233989651 100644 --- a/pkg/store/proxy.go +++ b/pkg/store/proxy.go @@ -561,6 +561,8 @@ func (s *ProxyStore) LabelNames(ctx context.Context, r *storepb.LabelNamesReques g.Go(func() error { resp, err := st.LabelNames(gctx, &storepb.LabelNamesRequest{ PartialResponseDisabled: r.PartialResponseDisabled, + Start: r.Start, + End: r.End, }) if err != nil { err = errors.Wrapf(err, "fetch label names from store %s", st) @@ -610,6 +612,8 @@ func (s *ProxyStore) LabelValues(ctx context.Context, r *storepb.LabelValuesRequ resp, err := store.LabelValues(gctx, &storepb.LabelValuesRequest{ Label: r.Label, PartialResponseDisabled: r.PartialResponseDisabled, + Start: r.Start, + End: r.End, }) if err != nil { err = errors.Wrapf(err, "fetch label values from store %s", store) diff --git a/pkg/store/proxy_test.go b/pkg/store/proxy_test.go index 50019ced37e..bf216f00dca 100644 --- a/pkg/store/proxy_test.go +++ b/pkg/store/proxy_test.go @@ -21,6 +21,7 @@ import ( "github.com/gogo/protobuf/types" "github.com/pkg/errors" "github.com/prometheus/prometheus/pkg/labels" + "github.com/prometheus/prometheus/pkg/timestamp" "github.com/prometheus/prometheus/tsdb/chunkenc" "github.com/thanos-io/thanos/pkg/component" "github.com/thanos-io/thanos/pkg/store/storepb" @@ -1098,6 +1099,8 @@ func TestProxyStore_LabelValues(t *testing.T) { req := &storepb.LabelValuesRequest{ Label: "a", PartialResponseDisabled: true, + Start: timestamp.FromTime(minTime), + End: timestamp.FromTime(maxTime), } resp, err := q.LabelValues(ctx, req) testutil.Ok(t, err) @@ -1139,6 +1142,8 @@ func TestProxyStore_LabelNames(t *testing.T) { }, }, req: &storepb.LabelNamesRequest{ + Start: timestamp.FromTime(minTime), + End: timestamp.FromTime(maxTime), PartialResponseDisabled: true, }, expectedNames: []string{"a", "b", "c", "d"}, @@ -1161,6 +1166,8 @@ func TestProxyStore_LabelNames(t *testing.T) { }, }, req: &storepb.LabelNamesRequest{ + Start: timestamp.FromTime(minTime), + End: timestamp.FromTime(maxTime), PartialResponseDisabled: true, }, expectedErr: errors.New("fetch label names from store test: error!"), @@ -1182,6 +1189,8 @@ func TestProxyStore_LabelNames(t *testing.T) { }, }, req: &storepb.LabelNamesRequest{ + Start: timestamp.FromTime(minTime), + End: timestamp.FromTime(maxTime), PartialResponseDisabled: false, }, expectedNames: []string{"a", "b"}, diff --git a/pkg/store/storepb/rpc.pb.go b/pkg/store/storepb/rpc.pb.go index bddab10d767..4c154f9a717 100644 --- a/pkg/store/storepb/rpc.pb.go +++ b/pkg/store/storepb/rpc.pb.go @@ -452,6 +452,8 @@ type LabelNamesRequest struct { PartialResponseDisabled bool `protobuf:"varint,1,opt,name=partial_response_disabled,json=partialResponseDisabled,proto3" json:"partial_response_disabled,omitempty"` // TODO(bwplotka): Move Thanos components to use strategy instead. Including QueryAPI. PartialResponseStrategy PartialResponseStrategy `protobuf:"varint,2,opt,name=partial_response_strategy,json=partialResponseStrategy,proto3,enum=thanos.PartialResponseStrategy" json:"partial_response_strategy,omitempty"` + Start int64 `protobuf:"varint,3,opt,name=start,proto3" json:"start,omitempty"` + End int64 `protobuf:"varint,4,opt,name=end,proto3" json:"end,omitempty"` } func (m *LabelNamesRequest) Reset() { *m = LabelNamesRequest{} } @@ -530,6 +532,8 @@ type LabelValuesRequest struct { PartialResponseDisabled bool `protobuf:"varint,2,opt,name=partial_response_disabled,json=partialResponseDisabled,proto3" json:"partial_response_disabled,omitempty"` // TODO(bwplotka): Move Thanos components to use strategy instead. Including QueryAPI. PartialResponseStrategy PartialResponseStrategy `protobuf:"varint,3,opt,name=partial_response_strategy,json=partialResponseStrategy,proto3,enum=thanos.PartialResponseStrategy" json:"partial_response_strategy,omitempty"` + Start int64 `protobuf:"varint,4,opt,name=start,proto3" json:"start,omitempty"` + End int64 `protobuf:"varint,5,opt,name=end,proto3" json:"end,omitempty"` } func (m *LabelValuesRequest) Reset() { *m = LabelValuesRequest{} } @@ -622,68 +626,70 @@ func init() { func init() { proto.RegisterFile("store/storepb/rpc.proto", fileDescriptor_a938d55a388af629) } var fileDescriptor_a938d55a388af629 = []byte{ - // 975 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x5b, 0x6f, 0xe3, 0x44, - 0x14, 0xb6, 0xe3, 0xc4, 0x49, 0x4e, 0xda, 0xe2, 0x9d, 0x5e, 0xd6, 0xcd, 0x4a, 0x69, 0x64, 0x09, - 0x29, 0x2a, 0xab, 0x04, 0x82, 0x00, 0x81, 0x78, 0x49, 0xdb, 0x2c, 0xad, 0xd8, 0xa6, 0x30, 0x69, - 0xb6, 0x5c, 0x84, 0x22, 0xb7, 0x9d, 0x75, 0xad, 0xf5, 0x0d, 0xcf, 0x84, 0x36, 0xaf, 0xf0, 0x8e, - 0xf8, 0x21, 0xfc, 0x0b, 0x84, 0xd4, 0xc7, 0x7d, 0x84, 0x17, 0x04, 0xed, 0x1f, 0x41, 0x73, 0x71, - 0x1a, 0x97, 0x6e, 0x25, 0xd4, 0x97, 0xc8, 0xe7, 0xfb, 0xce, 0xcc, 0xf9, 0xe6, 0x3b, 0x73, 0xec, - 0xc0, 0x63, 0xca, 0xe2, 0x94, 0x74, 0xc4, 0x6f, 0x72, 0xdc, 0x49, 0x93, 0x93, 0x76, 0x92, 0xc6, - 0x2c, 0x46, 0x26, 0x3b, 0x73, 0xa3, 0x98, 0xd6, 0xd7, 0xf3, 0x09, 0x6c, 0x9a, 0x10, 0x2a, 0x53, - 0xea, 0x2b, 0x5e, 0xec, 0xc5, 0xe2, 0xb1, 0xc3, 0x9f, 0x14, 0xda, 0xcc, 0x2f, 0x48, 0xd2, 0x38, - 0xbc, 0xb5, 0x6e, 0xdd, 0x8b, 0x63, 0x2f, 0x20, 0x1d, 0x11, 0x1d, 0x4f, 0x5e, 0x76, 0xdc, 0x68, - 0x2a, 0x29, 0xe7, 0x2d, 0x58, 0x3c, 0x4a, 0x7d, 0x46, 0x30, 0xa1, 0x49, 0x1c, 0x51, 0xe2, 0xfc, - 0xa4, 0xc3, 0x82, 0x42, 0xbe, 0x9f, 0x10, 0xca, 0x50, 0x0f, 0x80, 0xf9, 0x21, 0xa1, 0x24, 0xf5, - 0x09, 0xb5, 0xf5, 0xa6, 0xd1, 0xaa, 0x75, 0x9f, 0xf0, 0xd5, 0x21, 0x61, 0x67, 0x64, 0x42, 0xc7, - 0x27, 0x71, 0x32, 0x6d, 0x1f, 0xfa, 0x21, 0x19, 0x8a, 0x94, 0xad, 0xe2, 0xe5, 0x5f, 0x1b, 0x1a, - 0x9e, 0x5b, 0x84, 0xd6, 0xc0, 0x64, 0x24, 0x72, 0x23, 0x66, 0x17, 0x9a, 0x7a, 0xab, 0x8a, 0x55, - 0x84, 0x6c, 0x28, 0xa7, 0x24, 0x09, 0xfc, 0x13, 0xd7, 0x36, 0x9a, 0x7a, 0xcb, 0xc0, 0x59, 0xe8, - 0x2c, 0x42, 0x6d, 0x2f, 0x7a, 0x19, 0x2b, 0x0d, 0xce, 0x9f, 0x3a, 0x2c, 0xc8, 0x58, 0xaa, 0x44, - 0xef, 0x80, 0x19, 0xb8, 0xc7, 0x24, 0xc8, 0x04, 0x2d, 0xb6, 0xa5, 0x7b, 0xed, 0xe7, 0x1c, 0x55, - 0x12, 0x54, 0x0a, 0x5a, 0x87, 0x4a, 0xe8, 0x47, 0x63, 0x2e, 0x48, 0x08, 0x30, 0x70, 0x39, 0xf4, - 0x23, 0xae, 0x58, 0x50, 0xee, 0x85, 0xa4, 0x94, 0x84, 0xd0, 0xbd, 0x10, 0x54, 0x07, 0xaa, 0xc2, - 0xd2, 0xc3, 0x69, 0x42, 0xec, 0x62, 0x53, 0x6f, 0x2d, 0x75, 0x1f, 0x65, 0x55, 0x86, 0x19, 0x81, - 0x6f, 0x72, 0xd0, 0x07, 0x00, 0xa2, 0xe0, 0x98, 0x12, 0x46, 0xed, 0x92, 0xd0, 0x65, 0xe5, 0x74, - 0x0d, 0x09, 0x53, 0xd2, 0xaa, 0x81, 0x8a, 0xa9, 0xf3, 0x11, 0x54, 0x32, 0xf2, 0x7f, 0x1d, 0xcb, - 0xf9, 0xdd, 0x80, 0x45, 0x69, 0x79, 0xd6, 0xaa, 0xf9, 0x83, 0xea, 0x6f, 0x3e, 0x68, 0x21, 0x7f, - 0xd0, 0x0f, 0x39, 0xc5, 0x4e, 0xce, 0x48, 0x4a, 0x6d, 0x43, 0x94, 0x5d, 0xc9, 0x95, 0xdd, 0x97, - 0xa4, 0xaa, 0x3e, 0xcb, 0x45, 0x5d, 0x58, 0xe5, 0x5b, 0xa6, 0x84, 0xc6, 0xc1, 0x84, 0xf9, 0x71, - 0x34, 0x3e, 0xf7, 0xa3, 0xd3, 0xf8, 0x5c, 0x98, 0x65, 0xe0, 0xe5, 0xd0, 0xbd, 0xc0, 0x33, 0xee, - 0x48, 0x50, 0xe8, 0x29, 0x80, 0xeb, 0x79, 0x29, 0xf1, 0x5c, 0x46, 0xa4, 0x47, 0x4b, 0xdd, 0x85, - 0xac, 0x5a, 0xcf, 0xf3, 0x52, 0x3c, 0xc7, 0xa3, 0x4f, 0x60, 0x3d, 0x71, 0x53, 0xe6, 0xbb, 0x01, - 0xaf, 0x22, 0x3a, 0x3f, 0x3e, 0xf5, 0xa9, 0x7b, 0x1c, 0x90, 0x53, 0xdb, 0x6c, 0xea, 0xad, 0x0a, - 0x7e, 0xac, 0x12, 0xb2, 0x9b, 0xb1, 0xa3, 0x68, 0xf4, 0xed, 0x1d, 0x6b, 0x29, 0x4b, 0x5d, 0x46, - 0xbc, 0xa9, 0x5d, 0x16, 0xed, 0xdc, 0xc8, 0x0a, 0x7f, 0x91, 0xdf, 0x63, 0xa8, 0xd2, 0xfe, 0xb3, - 0x79, 0x46, 0xa0, 0x0d, 0xa8, 0xd1, 0x57, 0x7e, 0x32, 0x3e, 0x39, 0x9b, 0x44, 0xaf, 0xa8, 0x5d, - 0x11, 0x52, 0x80, 0x43, 0xdb, 0x02, 0x41, 0x9b, 0x50, 0x3a, 0xf3, 0x23, 0x46, 0xed, 0x6a, 0x53, - 0x17, 0x86, 0xca, 0x09, 0x6c, 0x67, 0x13, 0xd8, 0xee, 0x45, 0x53, 0x2c, 0x53, 0x9c, 0x9f, 0x75, - 0x58, 0xca, 0xfa, 0xa8, 0xae, 0x77, 0x0b, 0xcc, 0xd9, 0xbc, 0xf1, 0xf5, 0x4b, 0xb3, 0x8b, 0x27, - 0xd0, 0x5d, 0x0d, 0x2b, 0x1e, 0xd5, 0xa1, 0x7c, 0xee, 0xa6, 0x91, 0x1f, 0x79, 0x72, 0xb6, 0x76, - 0x35, 0x9c, 0x01, 0xe8, 0x69, 0x26, 0xc2, 0x78, 0xb3, 0x88, 0x5d, 0x4d, 0xc9, 0xd8, 0xaa, 0x80, - 0x99, 0x12, 0x3a, 0x09, 0x98, 0xf3, 0xab, 0x0e, 0x8f, 0x44, 0xe7, 0x07, 0x6e, 0x78, 0x73, 0xb9, - 0xee, 0x6d, 0x86, 0xfe, 0x80, 0x66, 0x14, 0x1e, 0xd6, 0x0c, 0xe7, 0x19, 0xa0, 0x79, 0xb5, 0xca, - 0xc2, 0x15, 0x28, 0x45, 0x1c, 0x10, 0x93, 0x54, 0xc5, 0x32, 0x40, 0x75, 0xa8, 0x28, 0x77, 0xa8, - 0x5d, 0x10, 0xc4, 0x2c, 0x76, 0x7e, 0xd3, 0xd5, 0x46, 0x2f, 0xdc, 0x60, 0x72, 0x73, 0xee, 0x15, - 0x28, 0x89, 0x81, 0x13, 0x67, 0xac, 0x62, 0x19, 0xdc, 0xef, 0x46, 0xe1, 0x01, 0x6e, 0x18, 0x0f, - 0x74, 0x63, 0x0f, 0x96, 0x73, 0x87, 0x50, 0x76, 0xac, 0x81, 0xf9, 0x83, 0x40, 0x94, 0x1f, 0x2a, - 0xba, 0xcf, 0x90, 0xcd, 0xef, 0xa0, 0x3a, 0x7b, 0xd1, 0xa1, 0x1a, 0x94, 0x47, 0x83, 0xcf, 0x07, - 0x07, 0x47, 0x03, 0x4b, 0x43, 0x55, 0x28, 0x7d, 0x39, 0xea, 0xe3, 0xaf, 0x2d, 0x1d, 0x55, 0xa0, - 0x88, 0x47, 0xcf, 0xfb, 0x56, 0x81, 0x67, 0x0c, 0xf7, 0x76, 0xfa, 0xdb, 0x3d, 0x6c, 0x19, 0x3c, - 0x63, 0x78, 0x78, 0x80, 0xfb, 0x56, 0x91, 0xe3, 0xb8, 0xbf, 0xdd, 0xdf, 0x7b, 0xd1, 0xb7, 0x4a, - 0x1c, 0xdf, 0xe9, 0x6f, 0x8d, 0x3e, 0xb3, 0xcc, 0xcd, 0x2d, 0x28, 0xf2, 0x89, 0x47, 0x65, 0x30, - 0x70, 0xef, 0x48, 0xee, 0xba, 0x7d, 0x30, 0x1a, 0x1c, 0x5a, 0x3a, 0xc7, 0x86, 0xa3, 0x7d, 0xab, - 0xc0, 0x1f, 0xf6, 0xf7, 0x06, 0x96, 0x21, 0x1e, 0x7a, 0x5f, 0xc9, 0xed, 0x44, 0x56, 0x1f, 0x5b, - 0xa5, 0xee, 0x8f, 0x05, 0x28, 0x09, 0x8d, 0xe8, 0x3d, 0x28, 0xf2, 0x2f, 0x04, 0x5a, 0xce, 0x9c, - 0x9b, 0xfb, 0x7e, 0xd4, 0x57, 0xf2, 0xa0, 0xf2, 0xe4, 0x63, 0x30, 0xe5, 0x3c, 0xa1, 0xd5, 0xfc, - 0x7c, 0x65, 0xcb, 0xd6, 0x6e, 0xc3, 0x72, 0xe1, 0xbb, 0x3a, 0xda, 0x06, 0xb8, 0xb9, 0x73, 0x68, - 0x3d, 0xf7, 0xbe, 0x9c, 0x9f, 0x9a, 0x7a, 0xfd, 0x2e, 0x4a, 0xd5, 0x7f, 0x06, 0xb5, 0xb9, 0x56, - 0xa1, 0x7c, 0x6a, 0xee, 0x12, 0xd6, 0x9f, 0xdc, 0xc9, 0xc9, 0x7d, 0xba, 0x03, 0x58, 0x12, 0x5f, - 0x6c, 0x7e, 0xbb, 0xa4, 0x19, 0x9f, 0x42, 0x0d, 0x93, 0x30, 0x66, 0x44, 0xe0, 0x68, 0x76, 0xfc, - 0xf9, 0x0f, 0x7b, 0x7d, 0xf5, 0x16, 0xaa, 0xfe, 0x00, 0x68, 0x5b, 0x6f, 0x5f, 0xfe, 0xd3, 0xd0, - 0x2e, 0xaf, 0x1a, 0xfa, 0xeb, 0xab, 0x86, 0xfe, 0xf7, 0x55, 0x43, 0xff, 0xe5, 0xba, 0xa1, 0xbd, - 0xbe, 0x6e, 0x68, 0x7f, 0x5c, 0x37, 0xb4, 0x6f, 0xca, 0xea, 0x8f, 0xc6, 0xb1, 0x29, 0xde, 0x23, - 0xef, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x1d, 0x24, 0xc2, 0x3f, 0xd2, 0x08, 0x00, 0x00, + // 1003 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x4d, 0x6f, 0x23, 0x45, + 0x13, 0xf6, 0x78, 0xec, 0xb1, 0x5d, 0x4e, 0xf2, 0xce, 0x76, 0x9c, 0xec, 0xc4, 0x2b, 0x39, 0xd6, + 0x48, 0xaf, 0x64, 0x85, 0x95, 0x0d, 0x46, 0x80, 0x40, 0x5c, 0x9c, 0xc4, 0x4b, 0x22, 0x36, 0x0e, + 0xb4, 0xe3, 0x0d, 0x1f, 0x42, 0xd6, 0x24, 0xe9, 0x9d, 0x8c, 0x76, 0xbe, 0x98, 0x6e, 0x93, 0xf8, + 0x0a, 0x77, 0xc4, 0x9f, 0x42, 0xca, 0x71, 0x0f, 0x1c, 0xe0, 0x82, 0x20, 0x39, 0xf2, 0x27, 0x50, + 0x7f, 0x8c, 0xed, 0x09, 0xd9, 0x48, 0x28, 0x5c, 0xac, 0xae, 0x7a, 0xaa, 0xbb, 0x9e, 0x7e, 0xaa, + 0x6a, 0xdc, 0xf0, 0x98, 0xb2, 0x28, 0x21, 0x1d, 0xf1, 0x1b, 0x9f, 0x74, 0x92, 0xf8, 0xb4, 0x1d, + 0x27, 0x11, 0x8b, 0x90, 0xc1, 0xce, 0x9d, 0x30, 0xa2, 0xf5, 0x8d, 0x6c, 0x00, 0x9b, 0xc6, 0x84, + 0xca, 0x90, 0x7a, 0xcd, 0x8d, 0xdc, 0x48, 0x2c, 0x3b, 0x7c, 0xa5, 0xbc, 0xcd, 0xec, 0x86, 0x38, + 0x89, 0x82, 0x5b, 0xfb, 0x36, 0xdc, 0x28, 0x72, 0x7d, 0xd2, 0x11, 0xd6, 0xc9, 0xe4, 0x65, 0xc7, + 0x09, 0xa7, 0x12, 0xb2, 0xff, 0x07, 0xcb, 0xc7, 0x89, 0xc7, 0x08, 0x26, 0x34, 0x8e, 0x42, 0x4a, + 0xec, 0x1f, 0x34, 0x58, 0x52, 0x9e, 0x6f, 0x27, 0x84, 0x32, 0xd4, 0x03, 0x60, 0x5e, 0x40, 0x28, + 0x49, 0x3c, 0x42, 0x2d, 0xad, 0xa9, 0xb7, 0xaa, 0xdd, 0x27, 0x7c, 0x77, 0x40, 0xd8, 0x39, 0x99, + 0xd0, 0xf1, 0x69, 0x14, 0x4f, 0xdb, 0x47, 0x5e, 0x40, 0x86, 0x22, 0x64, 0xbb, 0x70, 0xf5, 0xfb, + 0x66, 0x0e, 0x2f, 0x6c, 0x42, 0xeb, 0x60, 0x30, 0x12, 0x3a, 0x21, 0xb3, 0xf2, 0x4d, 0xad, 0x55, + 0xc1, 0xca, 0x42, 0x16, 0x94, 0x12, 0x12, 0xfb, 0xde, 0xa9, 0x63, 0xe9, 0x4d, 0xad, 0xa5, 0xe3, + 0xd4, 0xb4, 0x97, 0xa1, 0xba, 0x1f, 0xbe, 0x8c, 0x14, 0x07, 0xfb, 0x37, 0x0d, 0x96, 0xa4, 0x2d, + 0x59, 0xa2, 0xb7, 0xc0, 0xf0, 0x9d, 0x13, 0xe2, 0xa7, 0x84, 0x96, 0xdb, 0x52, 0xbd, 0xf6, 0x73, + 0xee, 0x55, 0x14, 0x54, 0x08, 0xda, 0x80, 0x72, 0xe0, 0x85, 0x63, 0x4e, 0x48, 0x10, 0xd0, 0x71, + 0x29, 0xf0, 0x42, 0xce, 0x58, 0x40, 0xce, 0xa5, 0x84, 0x14, 0x85, 0xc0, 0xb9, 0x14, 0x50, 0x07, + 0x2a, 0x42, 0xd2, 0xa3, 0x69, 0x4c, 0xac, 0x42, 0x53, 0x6b, 0xad, 0x74, 0x1f, 0xa5, 0x59, 0x86, + 0x29, 0x80, 0xe7, 0x31, 0xe8, 0x3d, 0x00, 0x91, 0x70, 0x4c, 0x09, 0xa3, 0x56, 0x51, 0xf0, 0x32, + 0x33, 0xbc, 0x86, 0x84, 0x29, 0x6a, 0x15, 0x5f, 0xd9, 0xd4, 0xfe, 0x00, 0xca, 0x29, 0xf8, 0xaf, + 0xae, 0x65, 0xff, 0xac, 0xc3, 0xb2, 0x94, 0x3c, 0x2d, 0xd5, 0xe2, 0x45, 0xb5, 0x37, 0x5f, 0x34, + 0x9f, 0xbd, 0xe8, 0xfb, 0x1c, 0x62, 0xa7, 0xe7, 0x24, 0xa1, 0x96, 0x2e, 0xd2, 0xd6, 0x32, 0x69, + 0x0f, 0x24, 0xa8, 0xb2, 0xcf, 0x62, 0x51, 0x17, 0xd6, 0xf8, 0x91, 0x09, 0xa1, 0x91, 0x3f, 0x61, + 0x5e, 0x14, 0x8e, 0x2f, 0xbc, 0xf0, 0x2c, 0xba, 0x10, 0x62, 0xe9, 0x78, 0x35, 0x70, 0x2e, 0xf1, + 0x0c, 0x3b, 0x16, 0x10, 0x7a, 0x0a, 0xe0, 0xb8, 0x6e, 0x42, 0x5c, 0x87, 0x11, 0xa9, 0xd1, 0x4a, + 0x77, 0x29, 0xcd, 0xd6, 0x73, 0xdd, 0x04, 0x2f, 0xe0, 0xe8, 0x23, 0xd8, 0x88, 0x9d, 0x84, 0x79, + 0x8e, 0xcf, 0xb3, 0x88, 0xca, 0x8f, 0xcf, 0x3c, 0xea, 0x9c, 0xf8, 0xe4, 0xcc, 0x32, 0x9a, 0x5a, + 0xab, 0x8c, 0x1f, 0xab, 0x80, 0xb4, 0x33, 0x76, 0x15, 0x8c, 0xbe, 0xbe, 0x63, 0x2f, 0x65, 0x89, + 0xc3, 0x88, 0x3b, 0xb5, 0x4a, 0xa2, 0x9c, 0x9b, 0x69, 0xe2, 0xcf, 0xb2, 0x67, 0x0c, 0x55, 0xd8, + 0x3f, 0x0e, 0x4f, 0x01, 0xb4, 0x09, 0x55, 0xfa, 0xca, 0x8b, 0xc7, 0xa7, 0xe7, 0x93, 0xf0, 0x15, + 0xb5, 0xca, 0x82, 0x0a, 0x70, 0xd7, 0x8e, 0xf0, 0xa0, 0x2d, 0x28, 0x9e, 0x7b, 0x21, 0xa3, 0x56, + 0xa5, 0xa9, 0x09, 0x41, 0xe5, 0x04, 0xb6, 0xd3, 0x09, 0x6c, 0xf7, 0xc2, 0x29, 0x96, 0x21, 0xf6, + 0x8f, 0x1a, 0xac, 0xa4, 0x75, 0x54, 0xed, 0xdd, 0x02, 0x63, 0x36, 0x6f, 0x7c, 0xff, 0xca, 0xac, + 0xf1, 0x84, 0x77, 0x2f, 0x87, 0x15, 0x8e, 0xea, 0x50, 0xba, 0x70, 0x92, 0xd0, 0x0b, 0x5d, 0x39, + 0x5b, 0x7b, 0x39, 0x9c, 0x3a, 0xd0, 0xd3, 0x94, 0x84, 0xfe, 0x66, 0x12, 0x7b, 0x39, 0x45, 0x63, + 0xbb, 0x0c, 0x46, 0x42, 0xe8, 0xc4, 0x67, 0xf6, 0x2f, 0x1a, 0x3c, 0x12, 0x95, 0x1f, 0x38, 0xc1, + 0xbc, 0xb9, 0xee, 0x2d, 0x86, 0xf6, 0x80, 0x62, 0xe4, 0x1f, 0x58, 0x8c, 0x1a, 0x14, 0x29, 0x73, + 0x12, 0xa6, 0x06, 0x58, 0x1a, 0xc8, 0x04, 0x9d, 0x84, 0x67, 0xaa, 0x17, 0xf9, 0xd2, 0x7e, 0x06, + 0x68, 0xf1, 0x56, 0x4a, 0xea, 0x1a, 0x14, 0x43, 0xee, 0x10, 0x13, 0x57, 0xc1, 0xd2, 0x40, 0x75, + 0x28, 0x2b, 0x15, 0xa9, 0x95, 0x17, 0xc0, 0xcc, 0xb6, 0xff, 0xd2, 0xd4, 0x41, 0x2f, 0x1c, 0x7f, + 0x32, 0xd7, 0xa7, 0x06, 0x45, 0x31, 0x98, 0x42, 0x8b, 0x0a, 0x96, 0xc6, 0xfd, 0xaa, 0xe5, 0x1f, + 0xa0, 0x9a, 0xfe, 0x5f, 0xa9, 0x56, 0xb8, 0x43, 0xb5, 0xe2, 0x5c, 0xb5, 0x7d, 0x58, 0xcd, 0x5c, + 0x56, 0xc9, 0xb6, 0x0e, 0xc6, 0x77, 0xc2, 0xa3, 0x74, 0x53, 0xd6, 0x7d, 0xc2, 0x6d, 0x7d, 0x03, + 0x95, 0xd9, 0x87, 0x13, 0x55, 0xa1, 0x34, 0x1a, 0x7c, 0x3a, 0x38, 0x3c, 0x1e, 0x98, 0x39, 0x54, + 0x81, 0xe2, 0xe7, 0xa3, 0x3e, 0xfe, 0xd2, 0xd4, 0x50, 0x19, 0x0a, 0x78, 0xf4, 0xbc, 0x6f, 0xe6, + 0x79, 0xc4, 0x70, 0x7f, 0xb7, 0xbf, 0xd3, 0xc3, 0xa6, 0xce, 0x23, 0x86, 0x47, 0x87, 0xb8, 0x6f, + 0x16, 0xb8, 0x1f, 0xf7, 0x77, 0xfa, 0xfb, 0x2f, 0xfa, 0x66, 0x91, 0xfb, 0x77, 0xfb, 0xdb, 0xa3, + 0x4f, 0x4c, 0x63, 0x6b, 0x1b, 0x0a, 0xfc, 0x0b, 0x82, 0x4a, 0xa0, 0xe3, 0xde, 0xb1, 0x3c, 0x75, + 0xe7, 0x70, 0x34, 0x38, 0x32, 0x35, 0xee, 0x1b, 0x8e, 0x0e, 0xcc, 0x3c, 0x5f, 0x1c, 0xec, 0x0f, + 0x4c, 0x5d, 0x2c, 0x7a, 0x5f, 0xc8, 0xe3, 0x44, 0x54, 0x1f, 0x9b, 0xc5, 0xee, 0xf7, 0x79, 0x28, + 0x0a, 0x8e, 0xe8, 0x1d, 0x28, 0xf0, 0x7f, 0x1c, 0xb4, 0x9a, 0x2a, 0xbc, 0xf0, 0x7f, 0x54, 0xaf, + 0x65, 0x9d, 0x4a, 0x93, 0x0f, 0xc1, 0x90, 0xf3, 0x89, 0xd6, 0xb2, 0xf3, 0x9a, 0x6e, 0x5b, 0xbf, + 0xed, 0x96, 0x1b, 0xdf, 0xd6, 0xd0, 0x0e, 0xc0, 0xbc, 0x37, 0xd1, 0x46, 0xe6, 0xfb, 0xbb, 0x38, + 0x85, 0xf5, 0xfa, 0x5d, 0x90, 0xca, 0xff, 0x0c, 0xaa, 0x0b, 0xa5, 0x42, 0xd9, 0xd0, 0x4c, 0xb3, + 0xd6, 0x9f, 0xdc, 0x89, 0xc9, 0x73, 0xba, 0x03, 0x58, 0x11, 0x2f, 0x00, 0xde, 0x85, 0x52, 0x8c, + 0x8f, 0xa1, 0x8a, 0x49, 0x10, 0x31, 0x22, 0xfc, 0x68, 0x76, 0xfd, 0xc5, 0x87, 0x42, 0x7d, 0xed, + 0x96, 0x57, 0x3d, 0x28, 0x72, 0xdb, 0xff, 0xbf, 0xfa, 0xb3, 0x91, 0xbb, 0xba, 0x6e, 0x68, 0xaf, + 0xaf, 0x1b, 0xda, 0x1f, 0xd7, 0x0d, 0xed, 0xa7, 0x9b, 0x46, 0xee, 0xf5, 0x4d, 0x23, 0xf7, 0xeb, + 0x4d, 0x23, 0xf7, 0x55, 0x49, 0x3d, 0x5c, 0x4e, 0x0c, 0xf1, 0x5d, 0x7a, 0xf7, 0xef, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x9f, 0xfa, 0x6e, 0x07, 0x22, 0x09, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1417,6 +1423,16 @@ func (m *LabelNamesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.End != 0 { + i = encodeVarintRpc(dAtA, i, uint64(m.End)) + i-- + dAtA[i] = 0x20 + } + if m.Start != 0 { + i = encodeVarintRpc(dAtA, i, uint64(m.Start)) + i-- + dAtA[i] = 0x18 + } if m.PartialResponseStrategy != 0 { i = encodeVarintRpc(dAtA, i, uint64(m.PartialResponseStrategy)) i-- @@ -1496,6 +1512,16 @@ func (m *LabelValuesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.End != 0 { + i = encodeVarintRpc(dAtA, i, uint64(m.End)) + i-- + dAtA[i] = 0x28 + } + if m.Start != 0 { + i = encodeVarintRpc(dAtA, i, uint64(m.Start)) + i-- + dAtA[i] = 0x20 + } if m.PartialResponseStrategy != 0 { i = encodeVarintRpc(dAtA, i, uint64(m.PartialResponseStrategy)) i-- @@ -1760,6 +1786,12 @@ func (m *LabelNamesRequest) Size() (n int) { if m.PartialResponseStrategy != 0 { n += 1 + sovRpc(uint64(m.PartialResponseStrategy)) } + if m.Start != 0 { + n += 1 + sovRpc(uint64(m.Start)) + } + if m.End != 0 { + n += 1 + sovRpc(uint64(m.End)) + } return n } @@ -1800,6 +1832,12 @@ func (m *LabelValuesRequest) Size() (n int) { if m.PartialResponseStrategy != 0 { n += 1 + sovRpc(uint64(m.PartialResponseStrategy)) } + if m.Start != 0 { + n += 1 + sovRpc(uint64(m.Start)) + } + if m.End != 0 { + n += 1 + sovRpc(uint64(m.End)) + } return n } @@ -2870,6 +2908,44 @@ func (m *LabelNamesRequest) Unmarshal(dAtA []byte) error { break } } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Start", wireType) + } + m.Start = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRpc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Start |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field End", wireType) + } + m.End = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRpc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.End |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipRpc(dAtA[iNdEx:]) @@ -3111,6 +3187,44 @@ func (m *LabelValuesRequest) Unmarshal(dAtA []byte) error { break } } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Start", wireType) + } + m.Start = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRpc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Start |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field End", wireType) + } + m.End = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRpc + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.End |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipRpc(dAtA[iNdEx:]) diff --git a/pkg/store/storepb/rpc.proto b/pkg/store/storepb/rpc.proto index 51a53c88d97..414998435a2 100644 --- a/pkg/store/storepb/rpc.proto +++ b/pkg/store/storepb/rpc.proto @@ -144,6 +144,10 @@ message LabelNamesRequest { // TODO(bwplotka): Move Thanos components to use strategy instead. Including QueryAPI. PartialResponseStrategy partial_response_strategy = 2; + + int64 start = 3; + + int64 end = 4; } message LabelNamesResponse { @@ -158,6 +162,10 @@ message LabelValuesRequest { // TODO(bwplotka): Move Thanos components to use strategy instead. Including QueryAPI. PartialResponseStrategy partial_response_strategy = 3; + + int64 start = 4; + + int64 end = 5; } message LabelValuesResponse { diff --git a/pkg/store/tsdb.go b/pkg/store/tsdb.go index 70454a39f50..ee7debc7766 100644 --- a/pkg/store/tsdb.go +++ b/pkg/store/tsdb.go @@ -214,10 +214,10 @@ func (s *TSDBStore) translateAndExtendLabels(m, extend labels.Labels) []storepb. } // LabelNames returns all known label names. -func (s *TSDBStore) LabelNames(ctx context.Context, _ *storepb.LabelNamesRequest) ( +func (s *TSDBStore) LabelNames(ctx context.Context, r *storepb.LabelNamesRequest) ( *storepb.LabelNamesResponse, error, ) { - q, err := s.db.Querier(ctx, math.MinInt64, math.MaxInt64) + q, err := s.db.Querier(ctx, r.Start, r.End) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -234,7 +234,7 @@ func (s *TSDBStore) LabelNames(ctx context.Context, _ *storepb.LabelNamesRequest func (s *TSDBStore) LabelValues(ctx context.Context, r *storepb.LabelValuesRequest) ( *storepb.LabelValuesResponse, error, ) { - q, err := s.db.Querier(ctx, math.MinInt64, math.MaxInt64) + q, err := s.db.Querier(ctx, r.Start, r.End) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/pkg/store/tsdb_test.go b/pkg/store/tsdb_test.go index 75f82cdd54d..c0aa6bf87c0 100644 --- a/pkg/store/tsdb_test.go +++ b/pkg/store/tsdb_test.go @@ -11,6 +11,7 @@ import ( "github.com/fortytw2/leaktest" "github.com/prometheus/prometheus/pkg/labels" + "github.com/prometheus/prometheus/pkg/timestamp" "github.com/thanos-io/thanos/pkg/component" "github.com/thanos-io/thanos/pkg/store/storepb" "github.com/thanos-io/thanos/pkg/testutil" @@ -188,40 +189,93 @@ func TestTSDBStore_LabelNames(t *testing.T) { testutil.Ok(t, err) appender := db.Appender() - addLabels := func(lbs []string) { + addLabels := func(lbs []string, timestamp int64) { if len(lbs) > 0 { - _, err = appender.Add(labels.FromStrings(lbs...), math.MaxInt64, 1) + _, err = appender.Add(labels.FromStrings(lbs...), timestamp, 1) testutil.Ok(t, err) } } tsdbStore := NewTSDBStore(nil, nil, db, component.Rule, labels.FromStrings("region", "eu-west")) + now := time.Now() + head := db.Head() for _, tc := range []struct { title string labels []string expectedNames []string + timestamp int64 + start func() int64 + end func() int64 }{ { title: "no label in tsdb", labels: []string{}, expectedNames: []string{}, + timestamp: now.Unix(), + start: func() int64 { + return timestamp.FromTime(minTime) + }, + end: func() int64 { + return timestamp.FromTime(maxTime) + }, }, { title: "add one label", labels: []string{"foo", "foo"}, expectedNames: []string{"foo"}, + timestamp: now.Unix(), + start: func() int64 { + return timestamp.FromTime(minTime) + }, + end: func() int64 { + return timestamp.FromTime(maxTime) + }, }, { title: "add another label", labels: []string{"bar", "bar"}, // We will get two labels here. expectedNames: []string{"bar", "foo"}, + timestamp: now.Unix(), + start: func() int64 { + return timestamp.FromTime(minTime) + }, + end: func() int64 { + return timestamp.FromTime(maxTime) + }, + }, + { + title: "query range outside tsdb head", + labels: []string{}, + expectedNames: []string{}, + timestamp: now.Unix(), + start: func() int64 { + return timestamp.FromTime(minTime) + }, + end: func() int64 { + return head.MinTime() - 1 + }, + }, + { + title: "get all labels", + labels: []string{"buz", "buz"}, + expectedNames: []string{"bar", "buz", "foo"}, + timestamp: now.Unix(), + start: func() int64 { + return timestamp.FromTime(minTime) + }, + end: func() int64 { + return timestamp.FromTime(maxTime) + }, }, } { if ok := t.Run(tc.title, func(t *testing.T) { - addLabels(tc.labels) - resp, err := tsdbStore.LabelNames(ctx, &storepb.LabelNamesRequest{}) + addLabels(tc.labels, tc.timestamp) + resp, err := tsdbStore.LabelNames(ctx, &storepb.LabelNamesRequest{ + Start: tc.start(), + End: tc.end(), + }) testutil.Ok(t, err) testutil.Equals(t, tc.expectedNames, resp.Names) testutil.Equals(t, 0, len(resp.Warnings)) @@ -243,43 +297,86 @@ func TestTSDBStore_LabelValues(t *testing.T) { testutil.Ok(t, err) appender := db.Appender() - addLabels := func(lbs []string) { + addLabels := func(lbs []string, timestamp int64) { if len(lbs) > 0 { - _, err = appender.Add(labels.FromStrings(lbs...), math.MaxInt64, 1) + _, err = appender.Add(labels.FromStrings(lbs...), timestamp, 1) testutil.Ok(t, err) } } tsdbStore := NewTSDBStore(nil, nil, db, component.Rule, labels.FromStrings("region", "eu-west")) + now := time.Now() + head := db.Head() for _, tc := range []struct { title string addedLabels []string queryLabel string expectedValues []string + timestamp int64 + start func() int64 + end func() int64 }{ { title: "no label in tsdb", addedLabels: []string{}, queryLabel: "foo", expectedValues: []string{}, + timestamp: now.Unix(), + start: func() int64 { + return timestamp.FromTime(minTime) + }, + end: func() int64 { + return timestamp.FromTime(maxTime) + }, }, { title: "add one label value", addedLabels: []string{"foo", "test"}, queryLabel: "foo", expectedValues: []string{"test"}, + timestamp: now.Unix(), + start: func() int64 { + return timestamp.FromTime(minTime) + }, + end: func() int64 { + return timestamp.FromTime(maxTime) + }, }, { title: "add another label value", addedLabels: []string{"foo", "test1"}, queryLabel: "foo", expectedValues: []string{"test", "test1"}, + timestamp: now.Unix(), + start: func() int64 { + return timestamp.FromTime(minTime) + }, + end: func() int64 { + return timestamp.FromTime(maxTime) + }, + }, + { + title: "query time range outside head", + addedLabels: []string{}, + queryLabel: "foo", + expectedValues: []string{}, + timestamp: now.Unix(), + start: func() int64 { + return timestamp.FromTime(minTime) + }, + end: func() int64 { + return head.MinTime() - 1 + }, }, } { if ok := t.Run(tc.title, func(t *testing.T) { - addLabels(tc.addedLabels) - resp, err := tsdbStore.LabelValues(ctx, &storepb.LabelValuesRequest{Label: tc.queryLabel}) + addLabels(tc.addedLabels, tc.timestamp) + resp, err := tsdbStore.LabelValues(ctx, &storepb.LabelValuesRequest{ + Label: tc.queryLabel, + Start: tc.start(), + End: tc.end(), + }) testutil.Ok(t, err) testutil.Equals(t, tc.expectedValues, resp.Values) testutil.Equals(t, 0, len(resp.Warnings)) diff --git a/pkg/testutil/e2eutil/prometheus.go b/pkg/testutil/e2eutil/prometheus.go index 1f87a837872..49492350a9d 100644 --- a/pkg/testutil/e2eutil/prometheus.go +++ b/pkg/testutil/e2eutil/prometheus.go @@ -37,7 +37,7 @@ import ( ) const ( - defaultPrometheusVersion = "v1.8.2-0.20200507164740-ecee9c8abfd1" // v2.18.1 + defaultPrometheusVersion = "v1.8.2-0.20200724121523-657ba532e42f" defaultAlertmanagerVersion = "v0.20.0" defaultMinioVersion = "RELEASE.2018-10-06T00-15-16Z" diff --git a/test/e2e/e2ethanos/services.go b/test/e2e/e2ethanos/services.go index bd5bbfb8a28..8cf9c6462fc 100644 --- a/test/e2e/e2ethanos/services.go +++ b/test/e2e/e2ethanos/services.go @@ -37,7 +37,7 @@ var defaultBackoffConfig = util.BackoffConfig{ // TODO(bwplotka): Run against multiple? func DefaultPrometheusImage() string { - return "quay.io/prometheus/prometheus:v2.18.1" + return "quay.io/prometheus/prometheus:v2.19.3" } func DefaultAlertmanagerImage() string { diff --git a/test/e2e/query_test.go b/test/e2e/query_test.go index 3229b2821f0..befc9e13fba 100644 --- a/test/e2e/query_test.go +++ b/test/e2e/query_test.go @@ -21,6 +21,7 @@ import ( "github.com/go-kit/kit/log" "github.com/pkg/errors" "github.com/prometheus/common/model" + "github.com/prometheus/prometheus/pkg/timestamp" "github.com/thanos-io/thanos/pkg/promclient" "github.com/thanos-io/thanos/pkg/runutil" @@ -247,6 +248,94 @@ func TestQueryExternalPrefixAndRoutePrefix(t *testing.T) { checkNetworkRequests(t, querierProxy.URL+"/"+externalPrefix+"/graph") } +func TestQueryLabelNames(t *testing.T) { + t.Parallel() + + s, err := e2e.NewScenario("e2e_test_query_label_names") + testutil.Ok(t, err) + t.Cleanup(e2ethanos.CleanScenario(t, s)) + + receiver, err := e2ethanos.NewReceiver(s.SharedDir(), s.NetworkName(), "1", 1) + testutil.Ok(t, err) + testutil.Ok(t, s.StartAndWaitReady(receiver)) + + prom1, sidecar1, err := e2ethanos.NewPrometheusWithSidecar(s.SharedDir(), s.NetworkName(), "alone", defaultPromConfig("prom-alone", 0, "", ""), e2ethanos.DefaultPrometheusImage()) + testutil.Ok(t, err) + prom2, sidecar2, err := e2ethanos.NewPrometheusWithSidecar(s.SharedDir(), s.NetworkName(), "remote-and-sidecar", defaultPromConfig("prom-both-remote-write-and-sidecar", 1234, e2ethanos.RemoteWriteEndpoint(receiver.NetworkEndpoint(8081)), ""), e2ethanos.DefaultPrometheusImage()) + testutil.Ok(t, err) + testutil.Ok(t, s.StartAndWaitReady(prom1, sidecar1, prom2, sidecar2)) + + q, err := e2ethanos.NewQuerier( + s.SharedDir(), + "1", + []string{sidecar1.GRPCNetworkEndpoint(), sidecar2.GRPCNetworkEndpoint(), receiver.GRPCNetworkEndpoint()}, + []string{}, + nil, + "", + "", + ) + + testutil.Ok(t, err) + testutil.Ok(t, s.StartAndWaitReady(q)) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + t.Cleanup(cancel) + + now := time.Now() + labelNames(t, ctx, q.HTTPEndpoint(), timestamp.FromTime(now.Add(-time.Hour)), timestamp.FromTime(now.Add(time.Hour)), func(res []string) bool { + return len(res) > 0 + }) + + // Outside time range. + labelNames(t, ctx, q.HTTPEndpoint(), timestamp.FromTime(now.Add(-24*time.Hour)), timestamp.FromTime(now.Add(-23*time.Hour)), func(res []string) bool { + return len(res) == 0 + }) +} + +func TestQueryLabelValues(t *testing.T) { + t.Parallel() + + s, err := e2e.NewScenario("e2e_test_query_label_values") + testutil.Ok(t, err) + t.Cleanup(e2ethanos.CleanScenario(t, s)) + + receiver, err := e2ethanos.NewReceiver(s.SharedDir(), s.NetworkName(), "1", 1) + testutil.Ok(t, err) + testutil.Ok(t, s.StartAndWaitReady(receiver)) + + prom1, sidecar1, err := e2ethanos.NewPrometheusWithSidecar(s.SharedDir(), s.NetworkName(), "alone", defaultPromConfig("prom-alone", 0, "", ""), e2ethanos.DefaultPrometheusImage()) + testutil.Ok(t, err) + prom2, sidecar2, err := e2ethanos.NewPrometheusWithSidecar(s.SharedDir(), s.NetworkName(), "remote-and-sidecar", defaultPromConfig("prom-both-remote-write-and-sidecar", 1234, e2ethanos.RemoteWriteEndpoint(receiver.NetworkEndpoint(8081)), ""), e2ethanos.DefaultPrometheusImage()) + testutil.Ok(t, err) + testutil.Ok(t, s.StartAndWaitReady(prom1, sidecar1, prom2, sidecar2)) + + q, err := e2ethanos.NewQuerier( + s.SharedDir(), + "1", + []string{sidecar1.GRPCNetworkEndpoint(), sidecar2.GRPCNetworkEndpoint(), receiver.GRPCNetworkEndpoint()}, + []string{}, + nil, + "", + "", + ) + + testutil.Ok(t, err) + testutil.Ok(t, s.StartAndWaitReady(q)) + + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + t.Cleanup(cancel) + + now := time.Now() + labelValues(t, ctx, q.HTTPEndpoint(), "instance", timestamp.FromTime(now.Add(-time.Hour)), timestamp.FromTime(now.Add(time.Hour)), func(res []string) bool { + return len(res) > 0 + }) + + // Outside time range. + labelValues(t, ctx, q.HTTPEndpoint(), "instance", timestamp.FromTime(now.Add(-24*time.Hour)), timestamp.FromTime(now.Add(-23*time.Hour)), func(res []string) bool { + return len(res) == 0 + }) +} + func checkNetworkRequests(t *testing.T, addr string) { ctx, cancel := chromedp.NewContext(context.Background()) t.Cleanup(cancel) @@ -332,3 +421,39 @@ func queryAndAssert(t *testing.T, ctx context.Context, addr string, q string, op } testutil.Equals(t, expected, result) } + +func labelNames(t *testing.T, ctx context.Context, addr string, start, end int64, check func(res []string) bool) { + t.Helper() + + logger := log.NewLogfmtLogger(os.Stdout) + logger = log.With(logger, "ts", log.DefaultTimestampUTC) + testutil.Ok(t, runutil.RetryWithLog(logger, time.Second, ctx.Done(), func() error { + res, err := promclient.NewDefaultClient().LabelNamesInGRPC(ctx, urlParse(t, "http://"+addr), start, end) + if err != nil { + return err + } + if check(res) { + return nil + } + + return errors.Errorf("unexpected results size %d", len(res)) + })) +} + +func labelValues(t *testing.T, ctx context.Context, addr, label string, start, end int64, check func(res []string) bool) { + t.Helper() + + logger := log.NewLogfmtLogger(os.Stdout) + logger = log.With(logger, "ts", log.DefaultTimestampUTC) + testutil.Ok(t, runutil.RetryWithLog(logger, time.Second, ctx.Done(), func() error { + res, err := promclient.NewDefaultClient().LabelValuesInGRPC(ctx, urlParse(t, "http://"+addr), label, start, end) + if err != nil { + return err + } + if check(res) { + return nil + } + + return errors.Errorf("unexpected results size %d", len(res)) + })) +}