From 55ad5f33ba7e3f9f41f30ee7b82c74e462f9d045 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Oct 2022 12:32:50 +0200 Subject: [PATCH 1/6] build(deps): bump github.com/digitalocean/godo from 1.84.1 to 1.86.0 (#11393) Bumps [github.com/digitalocean/godo](https://github.com/digitalocean/godo) from 1.84.1 to 1.86.0. - [Release notes](https://github.com/digitalocean/godo/releases) - [Changelog](https://github.com/digitalocean/godo/blob/main/CHANGELOG.md) - [Commits](https://github.com/digitalocean/godo/compare/v1.84.1...v1.86.0) --- updated-dependencies: - dependency-name: github.com/digitalocean/godo dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 071bef831b..71e2de5249 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/cespare/xxhash/v2 v2.1.2 github.com/dennwc/varint v1.0.0 github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245 - github.com/digitalocean/godo v1.84.1 + github.com/digitalocean/godo v1.86.0 github.com/docker/docker v20.10.18+incompatible github.com/edsrzf/mmap-go v1.1.0 github.com/envoyproxy/go-control-plane v0.10.3 @@ -60,7 +60,7 @@ require ( go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.1 go.uber.org/goleak v1.2.0 - golang.org/x/net v0.0.0-20220920203100-d0c6ba3f52d9 + golang.org/x/net v0.0.0-20220921155015-db77216a4ee9 golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 golang.org/x/sync v0.0.0-20220907140024-f12130a52804 golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 diff --git a/go.sum b/go.sum index 17b06cc4b7..2106fe624e 100644 --- a/go.sum +++ b/go.sum @@ -175,8 +175,8 @@ github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgz github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245 h1:9cOfvEwjQxdwKuNDTQSaMKNRvwKwgZG+U4HrjeRKHso= github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/digitalocean/godo v1.84.1 h1:VgPsuxhrO9pUygvij6qOhqXfAkxAsDZYRpmjSDMEaHo= -github.com/digitalocean/godo v1.84.1/go.mod h1:BPCqvwbjbGqxuUnIKB4EvS/AX7IDnNmt5fwvIkWo+ew= +github.com/digitalocean/godo v1.86.0 h1:GKB2HS+6lnYPn+9XLLsIVBWk3xk7v568EJnmdHuyhKA= +github.com/digitalocean/godo v1.86.0/go.mod h1:jELt1jkHVifd0rKaY0pt/m1QxGzbkkvoVVrDkR15/5A= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -1009,8 +1009,8 @@ golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220907135653-1e95f45603a7/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20220920203100-d0c6ba3f52d9 h1:asZqf0wXastQr+DudYagQS8uBO8bHKeYD1vbAvGmFL8= -golang.org/x/net v0.0.0-20220920203100-d0c6ba3f52d9/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220921155015-db77216a4ee9 h1:SdDGdqRuKrF2R4XGcnPzcvZ63c/55GvhoHUus0o+BNI= +golang.org/x/net v0.0.0-20220921155015-db77216a4ee9/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= From dc5af36d83be1703fb778c7869543a67fd15b2f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 13 Oct 2022 12:33:01 +0200 Subject: [PATCH 2/6] build(deps): bump google.golang.org/api from 0.96.0 to 0.98.0 (#11392) Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.96.0 to 0.98.0. - [Release notes](https://github.com/googleapis/google-api-go-client/releases) - [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.96.0...v0.98.0) --- updated-dependencies: - dependency-name: google.golang.org/api dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 71e2de5249..5a70c6626f 100644 --- a/go.mod +++ b/go.mod @@ -66,7 +66,7 @@ require ( golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 golang.org/x/time v0.0.0-20220920022843-2ce7c2934d45 golang.org/x/tools v0.1.12 - google.golang.org/api v0.96.0 + google.golang.org/api v0.98.0 google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006 google.golang.org/grpc v1.49.0 google.golang.org/protobuf v1.28.1 diff --git a/go.sum b/go.sum index 2106fe624e..ec45929d74 100644 --- a/go.sum +++ b/go.sum @@ -1279,8 +1279,8 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69 google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.96.0 h1:F60cuQPJq7K7FzsxMYHAUJSiXh2oKctHxBMbDygxhfM= -google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= +google.golang.org/api v0.98.0 h1:yxZrcxXESimy6r6mdL5Q6EnZwmewDJK2dVg3g75s5Dg= +google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= From 76b0d26be84b4f653e42c620a78850ad17b580c9 Mon Sep 17 00:00:00 2001 From: GabyCT Date: Fri, 14 Oct 2022 16:23:20 -0500 Subject: [PATCH 3/6] Update url for configuration.md doc (#11461) This PR updates the Serverset url at the configuration.md documentation. Signed-off-by: Gabriela Cervantes Signed-off-by: Gabriela Cervantes --- docs/configuration/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index 49affc393d..0b75ace8f7 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -2266,7 +2266,7 @@ tls_config: ### `` Serverset SD configurations allow retrieving scrape targets from [Serversets] -(https://github.com/twitter/finagle/tree/master/finagle-serversets) which are +(https://github.com/twitter/finagle/tree/develop/finagle-serversets) which are stored in [Zookeeper](https://zookeeper.apache.org/). Serversets are commonly used by [Finagle](https://twitter.github.io/finagle/) and [Aurora](https://aurora.apache.org/). From a5feccae6ee9b8c59b356f6ddf220e8928de8b6a Mon Sep 17 00:00:00 2001 From: Ganesh Vernekar Date: Wed, 19 Oct 2022 18:53:38 +0530 Subject: [PATCH 4/6] Add codesome as v2.40.0 release shepherd (#11475) Signed-off-by: Ganesh Vernekar Signed-off-by: Ganesh Vernekar --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 5cf09e58e2..6d5c7f0608 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -44,7 +44,7 @@ Release cadence of first pre-releases being cut is 6 weeks. | v2.37 LTS | 2022-06-29 | Julien Pivotto (GitHub: @roidelapluie) | | v2.38 | 2022-08-10 | Julius Volz (GitHub: @juliusv) | | v2.39 | 2022-09-21 | Ganesh Vernekar (GitHub: @codesome) | -| v2.40 | 2022-11-02 | **searching for volunteer** | +| v2.40 | 2022-11-02 | Ganesh Vernekar (GitHub: @codesome) | | v2.41 | 2022-12-14 | **searching for volunteer** | If you are interested in volunteering please create a pull request against the [prometheus/prometheus](https://github.com/prometheus/prometheus) repository and propose yourself for the release series of your choice. From 5ac12ac3517be1f1150d68e05df030edec4e85d4 Mon Sep 17 00:00:00 2001 From: Alan Protasio Date: Thu, 20 Oct 2022 02:17:00 -0700 Subject: [PATCH 5/6] api: Wrapped promQL based API errors with `returnAPIError` function (#11356) * wrap api error on get series/labels on `returnAPIError` function Signed-off-by: Alan Protasio * lint Signed-off-by: Alan Protasio * query exemplars Signed-off-by: Alan Protasio Signed-off-by: Alan Protasio --- web/api/v1/api.go | 12 +- web/api/v1/api_test.go | 283 ++++++++++++++++++++++++++++++++++++-- web/api/v1/errors_test.go | 5 + 3 files changed, 285 insertions(+), 15 deletions(-) diff --git a/web/api/v1/api.go b/web/api/v1/api.go index bd040912ef..1927ebb82b 100644 --- a/web/api/v1/api.go +++ b/web/api/v1/api.go @@ -550,12 +550,12 @@ func (api *API) queryExemplars(r *http.Request) apiFuncResult { ctx := r.Context() eq, err := api.ExemplarQueryable.ExemplarQuerier(ctx) if err != nil { - return apiFuncResult{nil, &apiError{errorExec, err}, nil, nil} + return apiFuncResult{nil, returnAPIError(err), nil, nil} } res, err := eq.Select(timestamp.FromTime(start), timestamp.FromTime(end), selectors...) if err != nil { - return apiFuncResult{nil, &apiError{errorExec, err}, nil, nil} + return apiFuncResult{nil, returnAPIError(err), nil, nil} } return apiFuncResult{res, nil, nil, nil} @@ -600,7 +600,7 @@ func (api *API) labelNames(r *http.Request) apiFuncResult { q, err := api.Queryable.Querier(r.Context(), timestamp.FromTime(start), timestamp.FromTime(end)) if err != nil { - return apiFuncResult{nil, &apiError{errorExec, err}, nil, nil} + return apiFuncResult{nil, returnAPIError(err), nil, nil} } defer q.Close() @@ -614,7 +614,7 @@ func (api *API) labelNames(r *http.Request) apiFuncResult { for _, matchers := range matcherSets { vals, callWarnings, err := q.LabelNames(matchers...) if err != nil { - return apiFuncResult{nil, &apiError{errorExec, err}, warnings, nil} + return apiFuncResult{nil, returnAPIError(err), warnings, nil} } warnings = append(warnings, callWarnings...) @@ -750,7 +750,7 @@ func (api *API) series(r *http.Request) (result apiFuncResult) { q, err := api.Queryable.Querier(r.Context(), timestamp.FromTime(start), timestamp.FromTime(end)) if err != nil { - return apiFuncResult{nil, &apiError{errorExec, err}, nil, nil} + return apiFuncResult{nil, returnAPIError(err), nil, nil} } // From now on, we must only return with a finalizer in the result (to // be called by the caller) or call q.Close ourselves (which is required @@ -791,7 +791,7 @@ func (api *API) series(r *http.Request) (result apiFuncResult) { warnings := set.Warnings() if set.Err() != nil { - return apiFuncResult{nil, &apiError{errorExec, set.Err()}, warnings, closer} + return apiFuncResult{nil, returnAPIError(set.Err()), warnings, closer} } return apiFuncResult{metrics, nil, warnings, closer} diff --git a/web/api/v1/api_test.go b/web/api/v1/api_test.go index d672807d3f..0fc0b39879 100644 --- a/web/api/v1/api_test.go +++ b/web/api/v1/api_test.go @@ -30,6 +30,7 @@ import ( "testing" "time" + "github.com/prometheus/prometheus/prompb" "github.com/prometheus/prometheus/util/stats" "github.com/go-kit/log" @@ -46,7 +47,6 @@ import ( "github.com/prometheus/prometheus/model/labels" "github.com/prometheus/prometheus/model/textparse" "github.com/prometheus/prometheus/model/timestamp" - "github.com/prometheus/prometheus/prompb" "github.com/prometheus/prometheus/promql" "github.com/prometheus/prometheus/promql/parser" "github.com/prometheus/prometheus/rules" @@ -452,7 +452,13 @@ func TestEndpoints(t *testing.T) { }) } -func TestLabelNames(t *testing.T) { +type byLabels []labels.Labels + +func (b byLabels) Len() int { return len(b) } +func (b byLabels) Swap(i, j int) { b[i], b[j] = b[j], b[i] } +func (b byLabels) Less(i, j int) bool { return labels.Compare(b[i], b[j]) < 0 } + +func TestGetSeries(t *testing.T) { // TestEndpoints doesn't have enough label names to test api.labelNames // endpoint properly. Hence we test it separately. suite, err := promql.NewTest(t, ` @@ -466,7 +472,6 @@ func TestLabelNames(t *testing.T) { require.NoError(t, err) defer suite.Close() require.NoError(t, suite.Run()) - api := &API{ Queryable: suite.Storage(), } @@ -487,28 +492,286 @@ func TestLabelNames(t *testing.T) { } for _, tc := range []struct { - name string - matchers []string - expected []string + name string + api *API + matchers []string + expected []labels.Labels + expectedErrorType errorType + }{ + { + name: "no matchers", + expectedErrorType: errorBadData, + api: api, + }, + { + name: "non empty label matcher", + matchers: []string{`{foo=~".+"}`}, + expected: []labels.Labels{ + {labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "abc", Value: "qwerty"}, labels.Label{Name: "foo", Value: "baz"}}, + {labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "foo", Value: "boo"}}, + {labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "foo", Value: "boo"}, labels.Label{Name: "xyz", Value: "qwerty"}}, + }, + api: api, + }, + { + name: "exact label matcher", + matchers: []string{`{foo="boo"}`}, + expected: []labels.Labels{ + {labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "foo", Value: "boo"}}, + {labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "foo", Value: "boo"}, labels.Label{Name: "xyz", Value: "qwerty"}}, + }, + api: api, + }, + { + name: "two matchers", + matchers: []string{`{foo="boo"}`, `{foo="baz"}`}, + expected: []labels.Labels{ + {labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "abc", Value: "qwerty"}, labels.Label{Name: "foo", Value: "baz"}}, + {labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "foo", Value: "boo"}}, + {labels.Label{Name: "__name__", Value: "test_metric2"}, labels.Label{Name: "foo", Value: "boo"}, labels.Label{Name: "xyz", Value: "qwerty"}}, + }, + api: api, + }, + { + name: "exec error type", + matchers: []string{`{foo="boo"}`, `{foo="baz"}`}, + expectedErrorType: errorExec, + api: &API{ + Queryable: errorTestQueryable{err: fmt.Errorf("generic")}, + }, + }, + { + name: "storage error type", + matchers: []string{`{foo="boo"}`, `{foo="baz"}`}, + expectedErrorType: errorInternal, + api: &API{ + Queryable: errorTestQueryable{err: promql.ErrStorage{Err: fmt.Errorf("generic")}}, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + ctx := context.Background() + req, err := request(http.MethodGet, tc.matchers...) + require.NoError(t, err) + res := tc.api.series(req.WithContext(ctx)) + assertAPIError(t, res.err, tc.expectedErrorType) + if tc.expectedErrorType == errorNone { + r := res.data.([]labels.Labels) + for _, l := range tc.expected { + sort.Sort(l) + } + for _, l := range r { + sort.Sort(l) + } + sort.Sort(byLabels(tc.expected)) + sort.Sort(byLabels(r)) + require.Equal(t, tc.expected, r) + } + }) + } +} + +func TestQueryExemplars(t *testing.T) { + start := time.Unix(0, 0) + suite, err := promql.NewTest(t, ` + load 1m + test_metric1{foo="bar"} 0+100x100 + test_metric1{foo="boo"} 1+0x100 + test_metric2{foo="boo"} 1+0x100 + test_metric3{foo="bar", dup="1"} 1+0x100 + test_metric3{foo="boo", dup="1"} 1+0x100 + test_metric4{foo="bar", dup="1"} 1+0x100 + test_metric4{foo="boo", dup="1"} 1+0x100 + test_metric4{foo="boo"} 1+0x100 + `) + + require.NoError(t, err) + defer suite.Close() + require.NoError(t, suite.Run()) + + api := &API{ + Queryable: suite.Storage(), + QueryEngine: suite.QueryEngine(), + ExemplarQueryable: suite.ExemplarQueryable(), + } + + request := func(method string, qs url.Values) (*http.Request, error) { + u, err := url.Parse("http://example.com") + require.NoError(t, err) + u.RawQuery = qs.Encode() + r, err := http.NewRequest(method, u.String(), nil) + if method == http.MethodPost { + r.Header.Set("Content-Type", "application/x-www-form-urlencoded") + } + return r, err + } + + for _, tc := range []struct { + name string + query url.Values + exemplars []exemplar.QueryResult + api *API + expectedErrorType errorType + }{ + { + name: "no error", + api: api, + query: url.Values{ + "query": []string{`test_metric3{foo="boo"} - test_metric4{foo="bar"}`}, + "start": []string{"0"}, + "end": []string{"4"}, + }, + exemplars: []exemplar.QueryResult{ + { + SeriesLabels: labels.FromStrings("__name__", "test_metric3", "foo", "boo", "dup", "1"), + Exemplars: []exemplar.Exemplar{ + { + Labels: labels.FromStrings("id", "abc"), + Value: 10, + Ts: timestamp.FromTime(start.Add(0 * time.Second)), + }, + }, + }, + { + SeriesLabels: labels.FromStrings("__name__", "test_metric4", "foo", "bar", "dup", "1"), + Exemplars: []exemplar.Exemplar{ + { + Labels: labels.FromStrings("id", "lul"), + Value: 10, + Ts: timestamp.FromTime(start.Add(3 * time.Second)), + }, + }, + }, + }, + }, + { + name: "should return errorExec upon genetic error", + expectedErrorType: errorExec, + api: &API{ + ExemplarQueryable: errorTestQueryable{err: fmt.Errorf("generic")}, + }, + query: url.Values{ + "query": []string{`test_metric3{foo="boo"} - test_metric4{foo="bar"}`}, + "start": []string{"0"}, + "end": []string{"4"}, + }, + }, + { + name: "should return errorInternal err type is ErrStorage", + expectedErrorType: errorInternal, + api: &API{ + ExemplarQueryable: errorTestQueryable{err: promql.ErrStorage{Err: fmt.Errorf("generic")}}, + }, + query: url.Values{ + "query": []string{`test_metric3{foo="boo"} - test_metric4{foo="bar"}`}, + "start": []string{"0"}, + "end": []string{"4"}, + }, + }, + } { + t.Run(tc.name, func(t *testing.T) { + es := suite.ExemplarStorage() + ctx := context.Background() + + for _, te := range tc.exemplars { + for _, e := range te.Exemplars { + _, err := es.AppendExemplar(0, te.SeriesLabels, e) + if err != nil { + t.Fatal(err) + } + } + } + + req, err := request(http.MethodGet, tc.query) + require.NoError(t, err) + res := tc.api.queryExemplars(req.WithContext(ctx)) + assertAPIError(t, res.err, tc.expectedErrorType) + + if tc.expectedErrorType == errorNone { + assertAPIResponse(t, res.data, tc.exemplars) + } + }) + } +} + +func TestLabelNames(t *testing.T) { + // TestEndpoints doesn't have enough label names to test api.labelNames + // endpoint properly. Hence we test it separately. + suite, err := promql.NewTest(t, ` + load 1m + test_metric1{foo1="bar", baz="abc"} 0+100x100 + test_metric1{foo2="boo"} 1+0x100 + test_metric2{foo="boo"} 1+0x100 + test_metric2{foo="boo", xyz="qwerty"} 1+0x100 + test_metric2{foo="baz", abc="qwerty"} 1+0x100 + `) + require.NoError(t, err) + defer suite.Close() + require.NoError(t, suite.Run()) + api := &API{ + Queryable: suite.Storage(), + } + request := func(method string, matchers ...string) (*http.Request, error) { + u, err := url.Parse("http://example.com") + require.NoError(t, err) + q := u.Query() + for _, matcher := range matchers { + q.Add("match[]", matcher) + } + u.RawQuery = q.Encode() + + r, err := http.NewRequest(method, u.String(), nil) + if method == http.MethodPost { + r.Header.Set("Content-Type", "application/x-www-form-urlencoded") + } + return r, err + } + + for _, tc := range []struct { + name string + api *API + matchers []string + expected []string + expectedErrorType errorType }{ { name: "no matchers", expected: []string{"__name__", "abc", "baz", "foo", "foo1", "foo2", "xyz"}, + api: api, }, { name: "non empty label matcher", matchers: []string{`{foo=~".+"}`}, expected: []string{"__name__", "abc", "foo", "xyz"}, + api: api, }, { name: "exact label matcher", matchers: []string{`{foo="boo"}`}, expected: []string{"__name__", "foo", "xyz"}, + api: api, }, { name: "two matchers", matchers: []string{`{foo="boo"}`, `{foo="baz"}`}, expected: []string{"__name__", "abc", "foo", "xyz"}, + api: api, + }, + { + name: "exec error type", + matchers: []string{`{foo="boo"}`, `{foo="baz"}`}, + expectedErrorType: errorExec, + api: &API{ + Queryable: errorTestQueryable{err: fmt.Errorf("generic")}, + }, + }, + { + name: "storage error type", + matchers: []string{`{foo="boo"}`, `{foo="baz"}`}, + expectedErrorType: errorInternal, + api: &API{ + Queryable: errorTestQueryable{err: promql.ErrStorage{Err: fmt.Errorf("generic")}}, + }, }, } { t.Run(tc.name, func(t *testing.T) { @@ -516,9 +779,11 @@ func TestLabelNames(t *testing.T) { ctx := context.Background() req, err := request(method, tc.matchers...) require.NoError(t, err) - res := api.labelNames(req.WithContext(ctx)) - assertAPIError(t, res.err, "") - assertAPIResponse(t, res.data, tc.expected) + res := tc.api.labelNames(req.WithContext(ctx)) + assertAPIError(t, res.err, tc.expectedErrorType) + if tc.expectedErrorType == errorNone { + assertAPIResponse(t, res.data, tc.expected) + } } }) } diff --git a/web/api/v1/errors_test.go b/web/api/v1/errors_test.go index 3c40c803af..90d5f18de3 100644 --- a/web/api/v1/errors_test.go +++ b/web/api/v1/errors_test.go @@ -141,10 +141,15 @@ func createPrometheusAPI(q storage.SampleAndChunkQueryable) *route.Router { } type errorTestQueryable struct { + storage.ExemplarQueryable q storage.Querier err error } +func (t errorTestQueryable) ExemplarQuerier(ctx context.Context) (storage.ExemplarQuerier, error) { + return nil, t.err +} + func (t errorTestQueryable) ChunkQuerier(ctx context.Context, mint, maxt int64) (storage.ChunkQuerier, error) { return nil, t.err } From 51a44e6657c3963b3e80b61b08c94a476987c7f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Ca=C3=B1adillas?= <41782403+dcanadillas@users.noreply.github.com> Date: Fri, 21 Oct 2022 14:13:01 +0200 Subject: [PATCH 6/6] Adding Consul Enterprise Admin Partitions (#11482) * Adding Consul Enterprise Admin Partitions Signed-off-by: dcanadillas --- discovery/consul/consul.go | 7 +++++++ docs/configuration/configuration.md | 3 +++ 2 files changed, 10 insertions(+) diff --git a/discovery/consul/consul.go b/discovery/consul/consul.go index 8d0a1fea48..c59bd1f5d8 100644 --- a/discovery/consul/consul.go +++ b/discovery/consul/consul.go @@ -60,6 +60,8 @@ const ( datacenterLabel = model.MetaLabelPrefix + "consul_dc" // namespaceLabel is the name of the label containing the namespace (Consul Enterprise only). namespaceLabel = model.MetaLabelPrefix + "consul_namespace" + // partitionLabel is the name of the label containing the Admin Partition (Consul Enterprise only). + partitionLabel = model.MetaLabelPrefix + "consul_partition" // taggedAddressesLabel is the prefix for the labels mapping to a target's tagged addresses. taggedAddressesLabel = model.MetaLabelPrefix + "consul_tagged_address_" // serviceIDLabel is the name of the label containing the service ID. @@ -112,6 +114,7 @@ type SDConfig struct { Token config.Secret `yaml:"token,omitempty"` Datacenter string `yaml:"datacenter,omitempty"` Namespace string `yaml:"namespace,omitempty"` + Partition string `yaml:"partition,omitempty"` TagSeparator string `yaml:"tag_separator,omitempty"` Scheme string `yaml:"scheme,omitempty"` Username string `yaml:"username,omitempty"` @@ -183,6 +186,7 @@ type Discovery struct { client *consul.Client clientDatacenter string clientNamespace string + clientPartition string tagSeparator string watchedServices []string // Set of services which will be discovered. watchedTags []string // Tags used to filter instances of a service. @@ -210,6 +214,7 @@ func NewDiscovery(conf *SDConfig, logger log.Logger) (*Discovery, error) { Scheme: conf.Scheme, Datacenter: conf.Datacenter, Namespace: conf.Namespace, + Partition: conf.Partition, Token: string(conf.Token), HttpClient: wrapper, } @@ -227,6 +232,7 @@ func NewDiscovery(conf *SDConfig, logger log.Logger) (*Discovery, error) { refreshInterval: time.Duration(conf.RefreshInterval), clientDatacenter: conf.Datacenter, clientNamespace: conf.Namespace, + clientPartition: conf.Partition, finalizer: wrapper.CloseIdleConnections, logger: logger, } @@ -547,6 +553,7 @@ func (srv *consulService) watch(ctx context.Context, ch chan<- []*targetgroup.Gr addressLabel: model.LabelValue(serviceNode.Node.Address), nodeLabel: model.LabelValue(serviceNode.Node.Node), namespaceLabel: model.LabelValue(serviceNode.Service.Namespace), + partitionLabel: model.LabelValue(serviceNode.Service.Partition), tagsLabel: model.LabelValue(tags), serviceAddressLabel: model.LabelValue(serviceNode.Service.Address), servicePortLabel: model.LabelValue(strconv.Itoa(serviceNode.Service.Port)), diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index 0b75ace8f7..dd6fb33f21 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -518,6 +518,7 @@ The following meta labels are available on targets during [relabeling](#relabel_ * `__meta_consul_address`: the address of the target * `__meta_consul_dc`: the datacenter name for the target * `__meta_consul_health`: the health status of the service +* `__meta_consul_partition`: the admin partition name where the service is registered * `__meta_consul_metadata_`: each node metadata key value of the target * `__meta_consul_node`: the node name defined for the target * `__meta_consul_service_address`: the service address of the target @@ -536,6 +537,8 @@ The following meta labels are available on targets during [relabeling](#relabel_ [ datacenter: ] # Namespaces are only supported in Consul Enterprise. [ namespace: ] +# Admin Partitions are only supported in Consul Enterprise. +[ partition: ] [ scheme: | default = "http" ] # The username and password fields are deprecated in favor of the basic_auth configuration. [ username: ]