From 8468a90774a09a99c5d55bdca901e91c1a2faf41 Mon Sep 17 00:00:00 2001 From: Bartlomiej Plotka Date: Thu, 28 Apr 2022 11:24:36 +0100 Subject: [PATCH 01/14] test: Added Alert compatibilty test. Signed-off-by: Bartlomiej Plotka --- test/e2e/compatibility_test.go | 85 ++++++++++++++++++++++++++++++- test/e2e/metadata_api_test.go | 12 ++--- test/e2e/query_test.go | 24 ++++----- test/e2e/rule_test.go | 6 +-- test/e2e/rules_api_test.go | 2 +- test/e2e/targets_api_test.go | 2 +- test/e2e/tools_bucket_web_test.go | 4 +- 7 files changed, 108 insertions(+), 27 deletions(-) diff --git a/test/e2e/compatibility_test.go b/test/e2e/compatibility_test.go index b8eb0930da..d90b69bd1e 100644 --- a/test/e2e/compatibility_test.go +++ b/test/e2e/compatibility_test.go @@ -5,6 +5,7 @@ package e2e_test import ( "io/ioutil" + "net/http" "os" "path/filepath" "testing" @@ -12,10 +13,16 @@ import ( "github.com/efficientgo/e2e" e2edb "github.com/efficientgo/e2e/db" + common_cfg "github.com/prometheus/common/config" + "github.com/prometheus/prometheus/config" + "github.com/thanos-io/thanos/pkg/alert" + "github.com/thanos-io/thanos/pkg/httpconfig" "github.com/thanos-io/thanos/pkg/testutil" "github.com/thanos-io/thanos/test/e2e/e2ethanos" ) +// TestPromQLCompliance tests PromQL compatibility. +// NOTE: This requires dockerization of compliance framework: https://github.com/prometheus/compliance/pull/46 // Test requires at least ~11m, so run this with `-test.timeout 9999m`. func TestPromQLCompliance(t *testing.T) { t.Skip("This is interactive test, it requires time to build up (scrape) the data. The data is also obtain from remote promlab servers.") @@ -24,7 +31,7 @@ func TestPromQLCompliance(t *testing.T) { testutil.Ok(t, err) t.Cleanup(e.Close) - // Start separate receive + Querier. + // Start receive + Querier. receiverRunnable, err := e2ethanos.NewIngestingReceiver(e, "receive") testutil.Ok(t, err) queryReceive := e2edb.NewThanosQuerier(e, "query_receive", []string{receiverRunnable.InternalEndpoint("grpc")}) @@ -53,7 +60,7 @@ scrape_configs: )) testutil.Ok(t, e2e.StartAndWaitReady(prom)) - // Start separate sidecar + Querier + // Start sidecar + Querier sidecar := e2edb.NewThanosSidecar(e, "sidecar", prom, e2edb.WithImage("thanos")) querySidecar := e2edb.NewThanosQuerier(e, "query_sidecar", []string{sidecar.InternalEndpoint("grpc")}, e2edb.WithImage("thanos")) testutil.Ok(t, e2e.StartAndWaitReady(sidecar, querySidecar)) @@ -105,3 +112,77 @@ query_tweaks: return ret }() } + +// TestAlertCompliance tests Alert compatibility against https://github.com/prometheus/compliance/blob/main/alert_generator/test-thanos.yaml. +func TestAlertCompliance_StatelessRuler(t *testing.T) { + t.Skip("This is an interactive test, mean to use with https://github.com/prometheus/compliance/tree/main/alert_generator") + + e, err := e2e.NewDockerEnvironment("alert_compatibility") + testutil.Ok(t, err) + t.Cleanup(e.Close) + + // Start receive + Querier. + receive, err := e2ethanos.NewIngestingReceiver(e, "receive") + testutil.Ok(t, err) + query := e2edb.NewThanosQuerier(e, "query_receive", []string{receive.InternalEndpoint("grpc")}) + ruler, err := e2ethanos.NewStatelessRuler(e, "1", "rules", []alert.AlertmanagerConfig{ + { + EndpointsConfig: httpconfig.EndpointsConfig{ + StaticAddresses: []string{}, + Scheme: "http", + }, + Timeout: amTimeout, + APIVersion: alert.APIv1, + }, + }, []httpconfig.Config{ + { + EndpointsConfig: httpconfig.EndpointsConfig{ + StaticAddresses: []string{ + query.InternalEndpoint("http"), + }, + Scheme: "http", + }, + }, + }, []*config.RemoteWriteConfig{ + {URL: &common_cfg.URL{URL: urlParse(t, e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("remote-write")))}, Name: "thanos-receiver"}, + }) + testutil.Ok(t, err) + testutil.Ok(t, e2e.StartAndWaitReady(receive, query, ruler)) + + // Pull fresh rules.yaml: + { + resp, err := http.Get("https://raw.githubusercontent.com/prometheus/compliance/main/alert_generator/rules.yaml") + testutil.Ok(t, err) + testutil.Equals(t, http.StatusOK, resp.StatusCode) + b, err := ioutil.ReadAll(resp.Body) + testutil.Ok(t, err) + testutil.Ok(t, os.WriteFile(filepath.Join(ruler.Dir(), "rules", "rules.yaml"), b, os.ModePerm)) + } + + compliance := e.Runnable("promql-compliance-tester").Init(e2e.StartOptions{ + Image: "promql-compliance-tester:latest", + Command: e2e.NewCommandWithoutEntrypoint("tail", "-f", "/dev/null"), + }) + testutil.Ok(t, e2e.StartAndWaitReady(compliance)) + + // Wait 10 minutes for Prometheus to scrape relevant data. + time.Sleep(10 * time.Minute) + + t.Run("receive", func(t *testing.T) { + testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "receive.yaml"), + []byte(promLabelsPromQLConfig(prom, query, []string{"prometheus", "receive", "tenant_id"})), os.ModePerm)) + + stdout, stderr, err := compliance.Exec(e2e.NewCommand("/promql-compliance-tester", "-config-file", filepath.Join(compliance.InternalDir(), "receive.yaml"))) + t.Log(stdout, stderr) + testutil.Ok(t, err) + }) + t.Run("sidecar", func(t *testing.T) { + testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "sidecar.yaml"), + []byte(promLabelsPromQLConfig(prom, querySidecar, []string{"prometheus"})), os.ModePerm)) + + stdout, stderr, err := compliance.Exec(e2e.NewCommand("/promql-compliance-tester", "-config-file", filepath.Join(compliance.InternalDir(), "sidecar.yaml"))) + t.Log(stdout, stderr) + testutil.Ok(t, err) + + }) +} diff --git a/test/e2e/metadata_api_test.go b/test/e2e/metadata_api_test.go index 00a87531b4..7369e2d45a 100644 --- a/test/e2e/metadata_api_test.go +++ b/test/e2e/metadata_api_test.go @@ -63,7 +63,7 @@ func TestMetadataAPI_Fanout(t *testing.T) { var promMeta map[string][]metadatapb.Meta // Wait metadata response to be ready as Prometheus gets metadata after scrape. testutil.Ok(t, runutil.Retry(5*time.Second, ctx.Done(), func() error { - promMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, mustURLParse(t, "http://"+prom1.Endpoint("http")), "", -1) + promMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+prom1.Endpoint("http")), "", -1) testutil.Ok(t, err) if len(promMeta) > 0 { return nil @@ -71,7 +71,7 @@ func TestMetadataAPI_Fanout(t *testing.T) { return fmt.Errorf("empty metadata response from Prometheus") })) - thanosMeta, err := promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, mustURLParse(t, "http://"+q.Endpoint("http")), "", -1) + thanosMeta, err := promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "", -1) testutil.Ok(t, err) testutil.Assert(t, len(thanosMeta) > 0, "got empty metadata response from Thanos") @@ -79,22 +79,22 @@ func TestMetadataAPI_Fanout(t *testing.T) { metadataEqual(t, thanosMeta, promMeta) // We only expect to see one metadata returned. - thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, mustURLParse(t, "http://"+q.Endpoint("http")), "", 1) + thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "", 1) testutil.Ok(t, err) testutil.Equals(t, len(thanosMeta), 1) // We only expect to see ten metadata returned. - thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, mustURLParse(t, "http://"+q.Endpoint("http")), "", 10) + thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "", 10) testutil.Ok(t, err) testutil.Equals(t, len(thanosMeta), 10) // No metadata returned. - thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, mustURLParse(t, "http://"+q.Endpoint("http")), "", 0) + thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "", 0) testutil.Ok(t, err) testutil.Equals(t, len(thanosMeta), 0) // Only prometheus_build_info metric will be returned. - thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, mustURLParse(t, "http://"+q.Endpoint("http")), "prometheus_build_info", -1) + thanosMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "prometheus_build_info", -1) testutil.Ok(t, err) testutil.Assert(t, len(thanosMeta) == 1 && len(thanosMeta["prometheus_build_info"]) > 0, "expected one prometheus_build_info metadata from Thanos, got %v", thanosMeta) } diff --git a/test/e2e/query_test.go b/test/e2e/query_test.go index 49e85467e5..50fcb8bbb5 100644 --- a/test/e2e/query_test.go +++ b/test/e2e/query_test.go @@ -223,7 +223,7 @@ func TestQueryExternalPrefix(t *testing.T) { testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(q)) - querierURL := mustURLParse(t, "http://"+q.Endpoint("http")+"/"+externalPrefix) + querierURL := urlParse(t, "http://"+q.Endpoint("http")+"/"+externalPrefix) querierProxy := httptest.NewServer(e2ethanos.NewSingleHostReverseProxy(querierURL, externalPrefix)) t.Cleanup(querierProxy.Close) @@ -248,7 +248,7 @@ func TestQueryExternalPrefixAndRoutePrefix(t *testing.T) { testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(q)) - querierURL := mustURLParse(t, "http://"+q.Endpoint("http")+"/"+routePrefix) + querierURL := urlParse(t, "http://"+q.Endpoint("http")+"/"+routePrefix) querierProxy := httptest.NewServer(e2ethanos.NewSingleHostReverseProxy(querierURL, externalPrefix)) t.Cleanup(querierProxy.Close) @@ -470,7 +470,7 @@ config: var promMeta map[string][]metadatapb.Meta // Wait metadata response to be ready as Prometheus gets metadata after scrape. testutil.Ok(t, runutil.Retry(3*time.Second, ctx.Done(), func() error { - promMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, mustURLParse(t, "http://"+p1.Endpoint("http")), "", -1) + promMeta, err = promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+p1.Endpoint("http")), "", -1) testutil.Ok(t, err) if len(promMeta) > 0 { return nil @@ -478,7 +478,7 @@ config: return fmt.Errorf("empty metadata response from Prometheus") })) - thanosMeta, err := promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, mustURLParse(t, "http://"+q.Endpoint("http")), "", -1) + thanosMeta, err := promclient.NewDefaultClient().MetricMetadataInGRPC(ctx, urlParse(t, "http://"+q.Endpoint("http")), "", -1) testutil.Ok(t, err) testutil.Assert(t, len(thanosMeta) > 0, "got empty metadata response from Thanos") @@ -886,7 +886,7 @@ func checkNetworkRequests(t *testing.T, addr string) { })) } -func mustURLParse(t testing.TB, addr string) *url.URL { +func urlParse(t testing.TB, addr string) *url.URL { u, err := url.Parse(addr) testutil.Ok(t, err) @@ -902,7 +902,7 @@ func instantQuery(t testing.TB, ctx context.Context, addr string, q func() strin logger := log.NewLogfmtLogger(os.Stdout) logger = log.With(logger, "ts", log.DefaultTimestampUTC) testutil.Ok(t, runutil.RetryWithLog(logger, 5*time.Second, ctx.Done(), func() error { - res, warnings, err := promclient.NewDefaultClient().QueryInstant(ctx, mustURLParse(t, "http://"+addr), q(), ts(), opts) + res, warnings, err := promclient.NewDefaultClient().QueryInstant(ctx, urlParse(t, "http://"+addr), q(), ts(), opts) if err != nil { return err } @@ -947,7 +947,7 @@ func labelNames(t *testing.T, ctx context.Context, addr string, matchers []*labe logger := log.NewLogfmtLogger(os.Stdout) logger = log.With(logger, "ts", log.DefaultTimestampUTC) testutil.Ok(t, runutil.RetryWithLog(logger, 2*time.Second, ctx.Done(), func() error { - res, err := promclient.NewDefaultClient().LabelNamesInGRPC(ctx, mustURLParse(t, "http://"+addr), matchers, start, end) + res, err := promclient.NewDefaultClient().LabelNamesInGRPC(ctx, urlParse(t, "http://"+addr), matchers, start, end) if err != nil { return err } @@ -966,7 +966,7 @@ func labelValues(t *testing.T, ctx context.Context, addr, label string, matchers logger := log.NewLogfmtLogger(os.Stdout) logger = log.With(logger, "ts", log.DefaultTimestampUTC) testutil.Ok(t, runutil.RetryWithLog(logger, 2*time.Second, ctx.Done(), func() error { - res, err := promclient.NewDefaultClient().LabelValuesInGRPC(ctx, mustURLParse(t, "http://"+addr), label, matchers, start, end) + res, err := promclient.NewDefaultClient().LabelValuesInGRPC(ctx, urlParse(t, "http://"+addr), label, matchers, start, end) if err != nil { return err } @@ -984,7 +984,7 @@ func series(t *testing.T, ctx context.Context, addr string, matchers []*labels.M logger := log.NewLogfmtLogger(os.Stdout) logger = log.With(logger, "ts", log.DefaultTimestampUTC) testutil.Ok(t, runutil.RetryWithLog(logger, 2*time.Second, ctx.Done(), func() error { - res, err := promclient.NewDefaultClient().SeriesInGRPC(ctx, mustURLParse(t, "http://"+addr), matchers, start, end) + res, err := promclient.NewDefaultClient().SeriesInGRPC(ctx, urlParse(t, "http://"+addr), matchers, start, end) if err != nil { return err } @@ -1003,7 +1003,7 @@ func rangeQuery(t *testing.T, ctx context.Context, addr string, q func() string, 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, warnings, err := promclient.NewDefaultClient().QueryRange(ctx, mustURLParse(t, "http://"+addr), q(), start, end, step, opts) + res, warnings, err := promclient.NewDefaultClient().QueryRange(ctx, urlParse(t, "http://"+addr), q(), start, end, step, opts) if err != nil { return err } @@ -1025,7 +1025,7 @@ func queryExemplars(t *testing.T, ctx context.Context, addr, q string, start, en logger := log.NewLogfmtLogger(os.Stdout) logger = log.With(logger, "ts", log.DefaultTimestampUTC) - u := mustURLParse(t, "http://"+addr) + u := urlParse(t, "http://"+addr) testutil.Ok(t, runutil.RetryWithLog(logger, time.Second, ctx.Done(), func() error { res, err := promclient.NewDefaultClient().ExemplarsInGRPC(ctx, u, q, start, end) if err != nil { @@ -1276,7 +1276,7 @@ func TestSidecarAlignmentPushdown(t *testing.T) { var expectedRes model.Matrix testutil.Ok(t, runutil.RetryWithLog(logger, time.Second, ctx.Done(), func() error { - res, warnings, err := promclient.NewDefaultClient().QueryRange(ctx, mustURLParse(t, "http://"+q1.Endpoint("http")), testQuery(), + res, warnings, err := promclient.NewDefaultClient().QueryRange(ctx, urlParse(t, "http://"+q1.Endpoint("http")), testQuery(), timestamp.FromTime(now.Add(time.Duration(-7*24)*time.Hour)), timestamp.FromTime(now), 2419, // Taken from UI. diff --git a/test/e2e/rule_test.go b/test/e2e/rule_test.go index f4e1f6f2c0..3ed1ff053c 100644 --- a/test/e2e/rule_test.go +++ b/test/e2e/rule_test.go @@ -452,7 +452,7 @@ func TestRule(t *testing.T) { }, } - alrts, err := promclient.NewDefaultClient().AlertmanagerAlerts(ctx, mustURLParse(t, "http://"+am2.Endpoint("http"))) + alrts, err := promclient.NewDefaultClient().AlertmanagerAlerts(ctx, urlParse(t, "http://"+am2.Endpoint("http"))) testutil.Ok(t, err) testutil.Equals(t, len(expAlertLabels), len(alrts)) @@ -490,12 +490,12 @@ func TestRule_CanRemoteWriteData(t *testing.T) { receiver, err := e2ethanos.NewIngestingReceiver(e, "1") testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(receiver)) - rwURL := mustURLParse(t, e2ethanos.RemoteWriteEndpoint(receiver.InternalEndpoint("remote-write"))) + rwURL := urlParse(t, e2ethanos.RemoteWriteEndpoint(receiver.InternalEndpoint("remote-write"))) receiver2, err := e2ethanos.NewIngestingReceiver(e, "2") testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(receiver2)) - rwURL2 := mustURLParse(t, e2ethanos.RemoteWriteEndpoint(receiver2.InternalEndpoint("remote-write"))) + rwURL2 := urlParse(t, e2ethanos.RemoteWriteEndpoint(receiver2.InternalEndpoint("remote-write"))) q, err := e2ethanos.NewQuerierBuilder(e, "1", receiver.InternalEndpoint("grpc"), receiver2.InternalEndpoint("grpc")).Build() testutil.Ok(t, err) diff --git a/test/e2e/rules_api_test.go b/test/e2e/rules_api_test.go index 624837cfc3..893ca21432 100644 --- a/test/e2e/rules_api_test.go +++ b/test/e2e/rules_api_test.go @@ -168,7 +168,7 @@ func ruleAndAssert(t *testing.T, ctx context.Context, addr, typ string, want []* logger := log.NewLogfmtLogger(os.Stdout) testutil.Ok(t, runutil.RetryWithLog(logger, time.Second, ctx.Done(), func() error { - res, err := promclient.NewDefaultClient().RulesInGRPC(ctx, mustURLParse(t, "http://"+addr), typ) + res, err := promclient.NewDefaultClient().RulesInGRPC(ctx, urlParse(t, "http://"+addr), typ) if err != nil { return err } diff --git a/test/e2e/targets_api_test.go b/test/e2e/targets_api_test.go index c8d5901965..10dd7f38cf 100644 --- a/test/e2e/targets_api_test.go +++ b/test/e2e/targets_api_test.go @@ -103,7 +103,7 @@ func targetAndAssert(t *testing.T, ctx context.Context, addr, state string, want logger := log.NewLogfmtLogger(os.Stdout) testutil.Ok(t, runutil.RetryWithLog(logger, time.Second, ctx.Done(), func() error { - res, err := promclient.NewDefaultClient().TargetsInGRPC(ctx, mustURLParse(t, "http://"+addr), state) + res, err := promclient.NewDefaultClient().TargetsInGRPC(ctx, urlParse(t, "http://"+addr), state) if err != nil { return err } diff --git a/test/e2e/tools_bucket_web_test.go b/test/e2e/tools_bucket_web_test.go index 5ce4621484..e2861ae6b4 100644 --- a/test/e2e/tools_bucket_web_test.go +++ b/test/e2e/tools_bucket_web_test.go @@ -95,7 +95,7 @@ func TestToolsBucketWebExternalPrefix(t *testing.T) { testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(b)) - toolsBucketWebURL := mustURLParse(t, "http://"+b.Endpoint("http")+"/"+externalPrefix) + toolsBucketWebURL := urlParse(t, "http://"+b.Endpoint("http")+"/"+externalPrefix) toolsBucketWebProxy := httptest.NewServer(e2ethanos.NewSingleHostReverseProxy(toolsBucketWebURL, externalPrefix)) t.Cleanup(toolsBucketWebProxy.Close) @@ -135,7 +135,7 @@ func TestToolsBucketWebExternalPrefixAndRoutePrefix(t *testing.T) { testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(b)) - toolsBucketWebURL := mustURLParse(t, "http://"+b.Endpoint("http")+"/"+routePrefix) + toolsBucketWebURL := urlParse(t, "http://"+b.Endpoint("http")+"/"+routePrefix) toolsBucketWebProxy := httptest.NewServer(e2ethanos.NewSingleHostReverseProxy(toolsBucketWebURL, externalPrefix)) t.Cleanup(toolsBucketWebProxy.Close) From 8fc03b91a4f1836aae7dcce8ef701e0e7cf62148 Mon Sep 17 00:00:00 2001 From: Bartlomiej Plotka Date: Thu, 28 Apr 2022 11:45:48 +0100 Subject: [PATCH 02/14] Tmp. Signed-off-by: Bartlomiej Plotka --- test/e2e/compatibility_test.go | 36 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/test/e2e/compatibility_test.go b/test/e2e/compatibility_test.go index d90b69bd1e..0eada75abd 100644 --- a/test/e2e/compatibility_test.go +++ b/test/e2e/compatibility_test.go @@ -25,7 +25,7 @@ import ( // NOTE: This requires dockerization of compliance framework: https://github.com/prometheus/compliance/pull/46 // Test requires at least ~11m, so run this with `-test.timeout 9999m`. func TestPromQLCompliance(t *testing.T) { - t.Skip("This is interactive test, it requires time to build up (scrape) the data. The data is also obtain from remote promlab servers.") + //t.Skip("This is interactive test, it requires time to build up (scrape) the data. The data is also obtain from remote promlab servers.") e, err := e2e.NewDockerEnvironment("compatibility") testutil.Ok(t, err) @@ -168,21 +168,21 @@ func TestAlertCompliance_StatelessRuler(t *testing.T) { // Wait 10 minutes for Prometheus to scrape relevant data. time.Sleep(10 * time.Minute) - t.Run("receive", func(t *testing.T) { - testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "receive.yaml"), - []byte(promLabelsPromQLConfig(prom, query, []string{"prometheus", "receive", "tenant_id"})), os.ModePerm)) - - stdout, stderr, err := compliance.Exec(e2e.NewCommand("/promql-compliance-tester", "-config-file", filepath.Join(compliance.InternalDir(), "receive.yaml"))) - t.Log(stdout, stderr) - testutil.Ok(t, err) - }) - t.Run("sidecar", func(t *testing.T) { - testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "sidecar.yaml"), - []byte(promLabelsPromQLConfig(prom, querySidecar, []string{"prometheus"})), os.ModePerm)) - - stdout, stderr, err := compliance.Exec(e2e.NewCommand("/promql-compliance-tester", "-config-file", filepath.Join(compliance.InternalDir(), "sidecar.yaml"))) - t.Log(stdout, stderr) - testutil.Ok(t, err) - - }) + //t.Run("receive", func(t *testing.T) { + // testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "receive.yaml"), + // []byte(promLabelsPromQLConfig(prom, query, []string{"prometheus", "receive", "tenant_id"})), os.ModePerm)) + // + // stdout, stderr, err := compliance.Exec(e2e.NewCommand("/promql-compliance-tester", "-config-file", filepath.Join(compliance.InternalDir(), "receive.yaml"))) + // t.Log(stdout, stderr) + // testutil.Ok(t, err) + //}) + //t.Run("sidecar", func(t *testing.T) { + // testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "sidecar.yaml"), + // []byte(promLabelsPromQLConfig(prom, querySidecar, []string{"prometheus"})), os.ModePerm)) + // + // stdout, stderr, err := compliance.Exec(e2e.NewCommand("/promql-compliance-tester", "-config-file", filepath.Join(compliance.InternalDir(), "sidecar.yaml"))) + // t.Log(stdout, stderr) + // testutil.Ok(t, err) + // + //}) } From fbb1b1d6787e6217747a70880b3e01cf8ec5e585 Mon Sep 17 00:00:00 2001 From: Bartlomiej Plotka Date: Thu, 28 Apr 2022 11:45:48 +0100 Subject: [PATCH 03/14] Update. Signed-off-by: Bartlomiej Plotka --- test/e2e/compatibility_test.go | 102 ++++++++++++++++++--------------- test/e2e/e2ethanos/services.go | 17 +++--- test/e2e/rule_test.go | 6 +- test/e2e/rules_api_test.go | 6 +- 4 files changed, 68 insertions(+), 63 deletions(-) diff --git a/test/e2e/compatibility_test.go b/test/e2e/compatibility_test.go index 0eada75abd..946685497e 100644 --- a/test/e2e/compatibility_test.go +++ b/test/e2e/compatibility_test.go @@ -4,8 +4,8 @@ package e2e_test import ( + "fmt" "io/ioutil" - "net/http" "os" "path/filepath" "testing" @@ -21,11 +21,11 @@ import ( "github.com/thanos-io/thanos/test/e2e/e2ethanos" ) -// TestPromQLCompliance tests PromQL compatibility. +// TestPromQLCompliance tests PromQL compatibility against https://github.com/prometheus/compliance/tree/main/promql. // NOTE: This requires dockerization of compliance framework: https://github.com/prometheus/compliance/pull/46 // Test requires at least ~11m, so run this with `-test.timeout 9999m`. func TestPromQLCompliance(t *testing.T) { - //t.Skip("This is interactive test, it requires time to build up (scrape) the data. The data is also obtain from remote promlab servers.") + t.Skip("This is interactive test, it requires time to build up (scrape) the data. The data is also obtain from remote promlab servers.") e, err := e2e.NewDockerEnvironment("compatibility") testutil.Ok(t, err) @@ -77,24 +77,31 @@ scrape_configs: t.Run("receive", func(t *testing.T) { testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "receive.yaml"), - []byte(promLabelsPromQLConfig(prom, queryReceive, []string{"prometheus", "receive", "tenant_id"})), os.ModePerm)) + []byte(promQLCompatConfig(prom, queryReceive, []string{"prometheus", "receive", "tenant_id"})), os.ModePerm)) - stdout, stderr, err := compliance.Exec(e2e.NewCommand("/promql-compliance-tester", "-config-file", filepath.Join(compliance.InternalDir(), "receive.yaml"))) + stdout, stderr, err := compliance.Exec(e2e.NewCommand( + "/promql-compliance-tester", + "-config-file", filepath.Join(compliance.InternalDir(), "receive.yaml"), + "-config-file", "/promql-test-queries.yml", + )) t.Log(stdout, stderr) testutil.Ok(t, err) }) t.Run("sidecar", func(t *testing.T) { testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "sidecar.yaml"), - []byte(promLabelsPromQLConfig(prom, querySidecar, []string{"prometheus"})), os.ModePerm)) + []byte(promQLCompatConfig(prom, querySidecar, []string{"prometheus"})), os.ModePerm)) - stdout, stderr, err := compliance.Exec(e2e.NewCommand("/promql-compliance-tester", "-config-file", filepath.Join(compliance.InternalDir(), "sidecar.yaml"))) + stdout, stderr, err := compliance.Exec(e2e.NewCommand( + "/promql-compliance-tester", + "-config-file", filepath.Join(compliance.InternalDir(), "sidecar.yaml"), + "-config-file", "/promql-test-queries.yml", + )) t.Log(stdout, stderr) testutil.Ok(t, err) - }) } -func promLabelsPromQLConfig(reference *e2edb.Prometheus, target e2e.Runnable, dropLabels []string) string { +func promQLCompatConfig(reference *e2edb.Prometheus, target e2e.Runnable, dropLabels []string) string { return `reference_target_config: query_url: 'http://` + reference.InternalEndpoint("http") + `' @@ -113,9 +120,14 @@ query_tweaks: }() } -// TestAlertCompliance tests Alert compatibility against https://github.com/prometheus/compliance/blob/main/alert_generator/test-thanos.yaml. +type alwaysReadyProbe struct{} + +func (p alwaysReadyProbe) Ready(e2e.Runnable) error { return nil } + +// TestAlertCompliance tests Alert compatibility against https://github.com/prometheus/compliance/blob/main/alert_generator. +// NOTE: This requires dockerization of compliance framework: https://github.com/prometheus/compliance/pull/46 func TestAlertCompliance_StatelessRuler(t *testing.T) { - t.Skip("This is an interactive test, mean to use with https://github.com/prometheus/compliance/tree/main/alert_generator") + t.Skip("This is an interactive test, using https://github.com/prometheus/compliance/tree/main/alert_generator testing is not optimized for CI runs") e, err := e2e.NewDockerEnvironment("alert_compatibility") testutil.Ok(t, err) @@ -125,10 +137,17 @@ func TestAlertCompliance_StatelessRuler(t *testing.T) { receive, err := e2ethanos.NewIngestingReceiver(e, "receive") testutil.Ok(t, err) query := e2edb.NewThanosQuerier(e, "query_receive", []string{receive.InternalEndpoint("grpc")}) - ruler, err := e2ethanos.NewStatelessRuler(e, "1", "rules", []alert.AlertmanagerConfig{ + + compliance := e.Runnable("alert_generator_compliance_tester").WithPorts(map[string]int{"http": 8080}).Init(e2e.StartOptions{ + Image: "alert_generator_compliance_tester:latest", + // Batch job with HTTP port, we will start it with Exec, no need for readiness. + Readiness: alwaysReadyProbe{}, + Command: e2e.NewCommandWithoutEntrypoint("tail", "-f", "/dev/null"), + }) + ruler := e2ethanos.NewStatelessRuler(e, "1", "rules", []alert.AlertmanagerConfig{ { EndpointsConfig: httpconfig.EndpointsConfig{ - StaticAddresses: []string{}, + StaticAddresses: []string{compliance.InternalEndpoint("http")}, Scheme: "http", }, Timeout: amTimeout, @@ -146,43 +165,34 @@ func TestAlertCompliance_StatelessRuler(t *testing.T) { }, []*config.RemoteWriteConfig{ {URL: &common_cfg.URL{URL: urlParse(t, e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("remote-write")))}, Name: "thanos-receiver"}, }) - testutil.Ok(t, err) - testutil.Ok(t, e2e.StartAndWaitReady(receive, query, ruler)) + testutil.Ok(t, e2e.StartAndWaitReady(receive, query, ruler, compliance)) - // Pull fresh rules.yaml: + // Pull rules.yaml: { - resp, err := http.Get("https://raw.githubusercontent.com/prometheus/compliance/main/alert_generator/rules.yaml") - testutil.Ok(t, err) - testutil.Equals(t, http.StatusOK, resp.StatusCode) - b, err := ioutil.ReadAll(resp.Body) - testutil.Ok(t, err) - testutil.Ok(t, os.WriteFile(filepath.Join(ruler.Dir(), "rules", "rules.yaml"), b, os.ModePerm)) + stdout, stderr, err := compliance.Exec(e2e.NewCommand("cat", "/rules.yaml")) + testutil.Ok(t, err, stderr) + testutil.Ok(t, os.MkdirAll(filepath.Join(ruler.Dir(), "rules"), os.ModePerm)) + testutil.Ok(t, os.WriteFile(filepath.Join(ruler.Dir(), "rules", "rules.yaml"), []byte(stdout), os.ModePerm)) } - compliance := e.Runnable("promql-compliance-tester").Init(e2e.StartOptions{ - Image: "promql-compliance-tester:latest", - Command: e2e.NewCommandWithoutEntrypoint("tail", "-f", "/dev/null"), - }) - testutil.Ok(t, e2e.StartAndWaitReady(compliance)) + testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "test-thanos.yaml"), + []byte(alertCompatConfig(receive, query)), os.ModePerm)) - // Wait 10 minutes for Prometheus to scrape relevant data. - time.Sleep(10 * time.Minute) + fmt.Println(alertCompatConfig(receive, query)) + + stdout, stderr, err := compliance.Exec(e2e.NewCommand( + "/alert_generator_compliance_tester", "-config-file", filepath.Join(compliance.InternalDir(), "test-thanos.yaml")), + ) + t.Log(stdout, stderr) + testutil.Ok(t, err) +} - //t.Run("receive", func(t *testing.T) { - // testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "receive.yaml"), - // []byte(promLabelsPromQLConfig(prom, query, []string{"prometheus", "receive", "tenant_id"})), os.ModePerm)) - // - // stdout, stderr, err := compliance.Exec(e2e.NewCommand("/promql-compliance-tester", "-config-file", filepath.Join(compliance.InternalDir(), "receive.yaml"))) - // t.Log(stdout, stderr) - // testutil.Ok(t, err) - //}) - //t.Run("sidecar", func(t *testing.T) { - // testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "sidecar.yaml"), - // []byte(promLabelsPromQLConfig(prom, querySidecar, []string{"prometheus"})), os.ModePerm)) - // - // stdout, stderr, err := compliance.Exec(e2e.NewCommand("/promql-compliance-tester", "-config-file", filepath.Join(compliance.InternalDir(), "sidecar.yaml"))) - // t.Log(stdout, stderr) - // testutil.Ok(t, err) - // - //}) +func alertCompatConfig(receive e2e.Runnable, query e2e.Runnable) string { + return `settings: + remote_write_url: '` + e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("http")) + `' + query_base_url: 'http://` + query.InternalEndpoint("http") + `' + rules_and_alerts_api_base_url: 'http://` + query.InternalEndpoint("http") + `' + alert_reception_server_port: 8080 + alert_message_parser: default +` } diff --git a/test/e2e/e2ethanos/services.go b/test/e2e/e2ethanos/services.go index 7a63d23ef1..c642db321e 100644 --- a/test/e2e/e2ethanos/services.go +++ b/test/e2e/e2ethanos/services.go @@ -560,32 +560,32 @@ func NewIngestingReceiver(e e2e.Environment, name string) (e2e.InstrumentedRunna return receiver, nil } -func NewTSDBRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config) (e2e.InstrumentedRunnable, error) { +func NewTSDBRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config) e2e.InstrumentedRunnable { return newRuler(e, name, ruleSubDir, amCfg, queryCfg, nil) } -func NewStatelessRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig) (e2e.InstrumentedRunnable, error) { +func NewStatelessRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig) e2e.InstrumentedRunnable { return newRuler(e, name, ruleSubDir, amCfg, queryCfg, remoteWriteCfg) } -func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig) (e2e.InstrumentedRunnable, error) { +func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig) e2e.InstrumentedRunnable { dir := filepath.Join(e.SharedDir(), "data", "rule", name) container := filepath.Join(ContainerSharedDir, "data", "rule", name) if err := os.MkdirAll(dir, 0750); err != nil { - return nil, errors.Wrap(err, "create rule dir") + return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "create rule dir")) } amCfgBytes, err := yaml.Marshal(alert.AlertingConfig{ Alertmanagers: amCfg, }) if err != nil { - return nil, errors.Wrapf(err, "generate am file: %v", amCfg) + return e2e.NewErrInstrumentedRunnable(name, errors.Wrapf(err, "generate am file: %v", amCfg)) } queryCfgBytes, err := yaml.Marshal(queryCfg) if err != nil { - return nil, errors.Wrapf(err, "generate query file: %v", queryCfg) + return e2e.NewErrInstrumentedRunnable(name, errors.Wrapf(err, "generate query file: %v", queryCfg)) } ruleArgs := map[string]string{ @@ -609,12 +609,12 @@ func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.Alertman RemoteWriteConfigs []*config.RemoteWriteConfig `yaml:"remote_write,omitempty"` }{remoteWriteCfg}) if err != nil { - return nil, errors.Wrapf(err, "generate remote write config: %v", remoteWriteCfg) + return e2e.NewErrInstrumentedRunnable(name, errors.Wrapf(err, "generate remote write config: %v", remoteWriteCfg)) } ruleArgs["--remote-write.config"] = string(rwCfgBytes) } - ruler := NewService(e, + return NewService(e, fmt.Sprintf("rule-%v", name), DefaultImage(), e2e.NewCommand("rule", e2e.BuildArgs(ruleArgs)...), @@ -623,7 +623,6 @@ func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.Alertman 9091, ) - return ruler, nil } func NewAlertmanager(e e2e.Environment, name string) (e2e.InstrumentedRunnable, error) { diff --git a/test/e2e/rule_test.go b/test/e2e/rule_test.go index 3ed1ff053c..d100a07d78 100644 --- a/test/e2e/rule_test.go +++ b/test/e2e/rule_test.go @@ -245,7 +245,7 @@ func TestRule(t *testing.T) { testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(am1, am2)) - r, err := e2ethanos.NewTSDBRuler(e, "1", rulesSubDir, []alert.AlertmanagerConfig{ + r := e2ethanos.NewTSDBRuler(e, "1", rulesSubDir, []alert.AlertmanagerConfig{ { EndpointsConfig: httpconfig.EndpointsConfig{ FileSDConfigs: []httpconfig.FileSDConfig{ @@ -278,7 +278,6 @@ func TestRule(t *testing.T) { }, }, }) - testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(r)) q, err := e2ethanos.NewQuerierBuilder(e, "1", r.InternalEndpoint("grpc")).Build() @@ -500,7 +499,7 @@ func TestRule_CanRemoteWriteData(t *testing.T) { q, err := e2ethanos.NewQuerierBuilder(e, "1", receiver.InternalEndpoint("grpc"), receiver2.InternalEndpoint("grpc")).Build() testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(q)) - r, err := e2ethanos.NewStatelessRuler(e, "1", rulesSubDir, []alert.AlertmanagerConfig{ + r := e2ethanos.NewStatelessRuler(e, "1", rulesSubDir, []alert.AlertmanagerConfig{ { EndpointsConfig: httpconfig.EndpointsConfig{ StaticAddresses: []string{ @@ -524,7 +523,6 @@ func TestRule_CanRemoteWriteData(t *testing.T) { {URL: &common_cfg.URL{URL: rwURL}, Name: "thanos-receiver"}, {URL: &common_cfg.URL{URL: rwURL2}, Name: "thanos-receiver2"}, }) - testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(r)) // Wait until remote write samples are written to receivers successfully. diff --git a/test/e2e/rules_api_test.go b/test/e2e/rules_api_test.go index 893ca21432..47db429b6a 100644 --- a/test/e2e/rules_api_test.go +++ b/test/e2e/rules_api_test.go @@ -78,10 +78,8 @@ func TestRulesAPI_Fanout(t *testing.T) { } // Recreate rulers with the corresponding query config. - r1, err := e2ethanos.NewTSDBRuler(e, "rule1", thanosRulesSubDir, nil, queryCfg) - testutil.Ok(t, err) - r2, err := e2ethanos.NewTSDBRuler(e, "rule2", thanosRulesSubDir, nil, queryCfg) - testutil.Ok(t, err) + r1 := e2ethanos.NewTSDBRuler(e, "rule1", thanosRulesSubDir, nil, queryCfg) + r2 := e2ethanos.NewTSDBRuler(e, "rule2", thanosRulesSubDir, nil, queryCfg) testutil.Ok(t, e2e.StartAndWaitReady(r1, r2)) stores := []string{sidecar1.InternalEndpoint("grpc"), sidecar2.InternalEndpoint("grpc"), r1.InternalEndpoint("grpc"), r2.InternalEndpoint("grpc")} From c11a4c2008f6ee7f1c97e78b632ee14d1d2dd5e5 Mon Sep 17 00:00:00 2001 From: Bartlomiej Plotka Date: Thu, 28 Apr 2022 21:49:15 +0100 Subject: [PATCH 04/14] update. Signed-off-by: Bartlomiej Plotka --- test/e2e/compatibility_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/compatibility_test.go b/test/e2e/compatibility_test.go index 946685497e..c4ed3c0504 100644 --- a/test/e2e/compatibility_test.go +++ b/test/e2e/compatibility_test.go @@ -127,7 +127,7 @@ func (p alwaysReadyProbe) Ready(e2e.Runnable) error { return nil } // TestAlertCompliance tests Alert compatibility against https://github.com/prometheus/compliance/blob/main/alert_generator. // NOTE: This requires dockerization of compliance framework: https://github.com/prometheus/compliance/pull/46 func TestAlertCompliance_StatelessRuler(t *testing.T) { - t.Skip("This is an interactive test, using https://github.com/prometheus/compliance/tree/main/alert_generator testing is not optimized for CI runs") + //t.Skip("This is an interactive test, using https://github.com/prometheus/compliance/tree/main/alert_generator testing is not optimized for CI runs") e, err := e2e.NewDockerEnvironment("alert_compatibility") testutil.Ok(t, err) From fa270461389fc7681c598244fa1d4f4ce48b9892 Mon Sep 17 00:00:00 2001 From: Bartlomiej Plotka Date: Thu, 28 Apr 2022 21:53:39 +0100 Subject: [PATCH 05/14] update. Signed-off-by: Bartlomiej Plotka --- go.mod | 7 +------ go.sum | 8 ++------ test/e2e/compatibility_test.go | 31 +++++++++++++++---------------- test/e2e/rule_test.go | 3 +-- 4 files changed, 19 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 63401edc0b..084c17826a 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/chromedp/chromedp v0.5.3 github.com/cortexproject/cortex v1.10.1-0.20211124141505-4e9fc3a2b5ab github.com/davecgh/go-spew v1.1.1 - github.com/efficientgo/e2e v0.11.2-0.20220224081107-b67f7b039363 + github.com/efficientgo/e2e v0.12.1-0.20220429160159-c0641fd0b1e6 github.com/efficientgo/tools/core v0.0.0-20210829154005-c7bad8450208 github.com/efficientgo/tools/extkingpin v0.0.0-20210609125236-d73259166f20 github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb @@ -123,12 +123,9 @@ require ( github.com/aws/aws-sdk-go-v2/service/sts v1.14.0 // indirect github.com/aws/smithy-go v1.10.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/containerd/cgroups v1.0.3 // indirect - github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/dennwc/varint v1.0.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dimchansky/utfbom v1.1.1 // indirect - github.com/docker/go-units v0.4.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/elastic/go-sysinfo v1.1.1 // indirect @@ -150,7 +147,6 @@ require ( github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee // indirect github.com/gobwas/pool v0.2.0 // indirect github.com/gobwas/ws v1.0.2 // indirect - github.com/godbus/dbus/v5 v5.0.6 // indirect github.com/gogo/googleapis v1.4.0 // indirect github.com/golang-jwt/jwt/v4 v4.0.0 // indirect github.com/golang/protobuf v1.5.2 // indirect @@ -179,7 +175,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mozillazg/go-httpheader v0.2.1 // indirect - github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 // indirect github.com/opentracing-contrib/go-grpc v0.0.0-20210225150812-73cb765af46e // indirect github.com/opentracing-contrib/go-stdlib v1.0.0 // indirect github.com/prometheus/common/sigv4 v0.1.0 // indirect diff --git a/go.sum b/go.sum index 48fba3f860..47516e118f 100644 --- a/go.sum +++ b/go.sum @@ -383,7 +383,6 @@ github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4S github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= -github.com/containerd/cgroups v1.0.3 h1:ADZftAkglvCiD44c77s5YmMqaP2pzVCFZvBmAlBdAP4= github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= @@ -587,8 +586,8 @@ github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= -github.com/efficientgo/e2e v0.11.2-0.20220224081107-b67f7b039363 h1:wlimY9L7RuHjNugLWsYH1wFTpkonEc3rktYSLx8aXu0= -github.com/efficientgo/e2e v0.11.2-0.20220224081107-b67f7b039363/go.mod h1:vDnF4AAEZmO0mvyFIATeDJPFaSRM7ywaOnKd61zaSoE= +github.com/efficientgo/e2e v0.12.1-0.20220429160159-c0641fd0b1e6 h1:C12Pfi3esBESKKB8dEOdcLiQ6Xif0kruf8sxgAjHHeU= +github.com/efficientgo/e2e v0.12.1-0.20220429160159-c0641fd0b1e6/go.mod h1:xDHUyIqAWyVWU29Lf+BaZoavW7xAbDEvTwHWWI/3bhk= github.com/efficientgo/tools/core v0.0.0-20210731122119-5d4a0645ce9a h1:Az9zRvQubUIHE+tHAm0gG7Dwge08V8Q/9uNSIFjFm+A= github.com/efficientgo/tools/core v0.0.0-20210731122119-5d4a0645ce9a/go.mod h1:OmVcnJopJL8d3X3sSXTiypGoUSgFq1aDGmlrdi9dn/M= github.com/efficientgo/tools/extkingpin v0.0.0-20210609125236-d73259166f20 h1:kM/ALyvAnTrwSB+nlKqoKaDnZbInp1YImZvW+gtHwc8= @@ -836,11 +835,9 @@ github.com/gocql/gocql v0.0.0-20200526081602-cd04bd7f22a7/go.mod h1:DL0ekTmBSTdl github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= -github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e h1:BWhy2j3IXJhjCbC68FptL43tDKIq8FladmaTs3Xs7Z8= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro= github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -1475,7 +1472,6 @@ github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/ github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc= github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= diff --git a/test/e2e/compatibility_test.go b/test/e2e/compatibility_test.go index c4ed3c0504..6b6c7e18fd 100644 --- a/test/e2e/compatibility_test.go +++ b/test/e2e/compatibility_test.go @@ -4,6 +4,7 @@ package e2e_test import ( + "bytes" "fmt" "io/ioutil" "os" @@ -79,28 +80,25 @@ scrape_configs: testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "receive.yaml"), []byte(promQLCompatConfig(prom, queryReceive, []string{"prometheus", "receive", "tenant_id"})), os.ModePerm)) - stdout, stderr, err := compliance.Exec(e2e.NewCommand( + testutil.Ok(t, compliance.Exec(e2e.NewCommand( "/promql-compliance-tester", "-config-file", filepath.Join(compliance.InternalDir(), "receive.yaml"), "-config-file", "/promql-test-queries.yml", - )) - t.Log(stdout, stderr) - testutil.Ok(t, err) + ))) }) t.Run("sidecar", func(t *testing.T) { testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "sidecar.yaml"), []byte(promQLCompatConfig(prom, querySidecar, []string{"prometheus"})), os.ModePerm)) - stdout, stderr, err := compliance.Exec(e2e.NewCommand( + testutil.Ok(t, compliance.Exec(e2e.NewCommand( "/promql-compliance-tester", "-config-file", filepath.Join(compliance.InternalDir(), "sidecar.yaml"), "-config-file", "/promql-test-queries.yml", - )) - t.Log(stdout, stderr) - testutil.Ok(t, err) + ))) }) } +// nolint (it's still used in skipped test). func promQLCompatConfig(reference *e2edb.Prometheus, target e2e.Runnable, dropLabels []string) string { return `reference_target_config: query_url: 'http://` + reference.InternalEndpoint("http") + `' @@ -120,14 +118,16 @@ query_tweaks: }() } +// nolint (it's still used in skipped test). type alwaysReadyProbe struct{} +// nolint (it's still used in skipped test). func (p alwaysReadyProbe) Ready(e2e.Runnable) error { return nil } // TestAlertCompliance tests Alert compatibility against https://github.com/prometheus/compliance/blob/main/alert_generator. // NOTE: This requires dockerization of compliance framework: https://github.com/prometheus/compliance/pull/46 func TestAlertCompliance_StatelessRuler(t *testing.T) { - //t.Skip("This is an interactive test, using https://github.com/prometheus/compliance/tree/main/alert_generator testing is not optimized for CI runs") + t.Skip("This is an interactive test, using https://github.com/prometheus/compliance/tree/main/alert_generator testing is not optimized for CI runs") e, err := e2e.NewDockerEnvironment("alert_compatibility") testutil.Ok(t, err) @@ -169,10 +169,10 @@ func TestAlertCompliance_StatelessRuler(t *testing.T) { // Pull rules.yaml: { - stdout, stderr, err := compliance.Exec(e2e.NewCommand("cat", "/rules.yaml")) - testutil.Ok(t, err, stderr) + var stdout bytes.Buffer + testutil.Ok(t, compliance.Exec(e2e.NewCommand("cat", "/rules.yaml"), e2e.WithExecOptionStdout(&stdout))) testutil.Ok(t, os.MkdirAll(filepath.Join(ruler.Dir(), "rules"), os.ModePerm)) - testutil.Ok(t, os.WriteFile(filepath.Join(ruler.Dir(), "rules", "rules.yaml"), []byte(stdout), os.ModePerm)) + testutil.Ok(t, os.WriteFile(filepath.Join(ruler.Dir(), "rules", "rules.yaml"), stdout.Bytes(), os.ModePerm)) } testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "test-thanos.yaml"), @@ -180,13 +180,12 @@ func TestAlertCompliance_StatelessRuler(t *testing.T) { fmt.Println(alertCompatConfig(receive, query)) - stdout, stderr, err := compliance.Exec(e2e.NewCommand( + testutil.Ok(t, compliance.Exec(e2e.NewCommand( "/alert_generator_compliance_tester", "-config-file", filepath.Join(compliance.InternalDir(), "test-thanos.yaml")), - ) - t.Log(stdout, stderr) - testutil.Ok(t, err) + )) } +// nolint (it's still used in skipped test). func alertCompatConfig(receive e2e.Runnable, query e2e.Runnable) string { return `settings: remote_write_url: '` + e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("http")) + `' diff --git a/test/e2e/rule_test.go b/test/e2e/rule_test.go index d100a07d78..7c41fd5c8b 100644 --- a/test/e2e/rule_test.go +++ b/test/e2e/rule_test.go @@ -154,8 +154,7 @@ func reloadRulesHTTP(t *testing.T, ctx context.Context, endpoint string) { func reloadRulesSignal(t *testing.T, r e2e.InstrumentedRunnable) { c := e2e.NewCommand("kill", "-1", "1") - _, _, err := r.Exec(c) - testutil.Ok(t, err) + testutil.Ok(t, r.Exec(c)) } func checkReloadSuccessful(t *testing.T, ctx context.Context, endpoint string, expectedRulegroupCount int) { From d35e0dd8cdf71048288dbf37314f5e0d0dc066f2 Mon Sep 17 00:00:00 2001 From: Bartlomiej Plotka Date: Mon, 9 May 2022 18:58:49 +0200 Subject: [PATCH 06/14] e2e: Refactored service helpers for newest e2e version. Signed-off-by: Bartlomiej Plotka --- go.mod | 2 +- go.sum | 4 +- test/e2e/compact_test.go | 20 +- test/e2e/compatibility_test.go | 120 +++--- test/e2e/e2ethanos/service.go | 77 ---- test/e2e/e2ethanos/services.go | 593 ++++++++++++------------------ test/e2e/exemplars_api_test.go | 20 +- test/e2e/info_api_test.go | 21 +- test/e2e/metadata_api_test.go | 12 +- test/e2e/query_frontend_test.go | 18 +- test/e2e/query_test.go | 163 ++++---- test/e2e/receive_test.go | 240 ++++-------- test/e2e/rule_test.go | 44 +-- test/e2e/rules_api_test.go | 34 +- test/e2e/store_gateway_test.go | 49 +-- test/e2e/targets_api_test.go | 10 +- test/e2e/tools_bucket_web_test.go | 40 +- 17 files changed, 536 insertions(+), 931 deletions(-) delete mode 100644 test/e2e/e2ethanos/service.go diff --git a/go.mod b/go.mod index 084c17826a..023c7397db 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/chromedp/chromedp v0.5.3 github.com/cortexproject/cortex v1.10.1-0.20211124141505-4e9fc3a2b5ab github.com/davecgh/go-spew v1.1.1 - github.com/efficientgo/e2e v0.12.1-0.20220429160159-c0641fd0b1e6 + github.com/efficientgo/e2e v0.12.1 github.com/efficientgo/tools/core v0.0.0-20210829154005-c7bad8450208 github.com/efficientgo/tools/extkingpin v0.0.0-20210609125236-d73259166f20 github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb diff --git a/go.sum b/go.sum index 47516e118f..7c5e6ab006 100644 --- a/go.sum +++ b/go.sum @@ -586,8 +586,8 @@ github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= -github.com/efficientgo/e2e v0.12.1-0.20220429160159-c0641fd0b1e6 h1:C12Pfi3esBESKKB8dEOdcLiQ6Xif0kruf8sxgAjHHeU= -github.com/efficientgo/e2e v0.12.1-0.20220429160159-c0641fd0b1e6/go.mod h1:xDHUyIqAWyVWU29Lf+BaZoavW7xAbDEvTwHWWI/3bhk= +github.com/efficientgo/e2e v0.12.1 h1:ZYNTf09ptlba0I3ZStYaF7gCbevWdalriiX7usOSiFM= +github.com/efficientgo/e2e v0.12.1/go.mod h1:xDHUyIqAWyVWU29Lf+BaZoavW7xAbDEvTwHWWI/3bhk= github.com/efficientgo/tools/core v0.0.0-20210731122119-5d4a0645ce9a h1:Az9zRvQubUIHE+tHAm0gG7Dwge08V8Q/9uNSIFjFm+A= github.com/efficientgo/tools/core v0.0.0-20210731122119-5d4a0645ce9a/go.mod h1:OmVcnJopJL8d3X3sSXTiypGoUSgFq1aDGmlrdi9dn/M= github.com/efficientgo/tools/extkingpin v0.0.0-20210609125236-d73259166f20 h1:kM/ALyvAnTrwSB+nlKqoKaDnZbInp1YImZvW+gtHwc8= diff --git a/test/e2e/compact_test.go b/test/e2e/compact_test.go index cd05cd5e42..a47fce0401 100644 --- a/test/e2e/compact_test.go +++ b/test/e2e/compact_test.go @@ -344,8 +344,7 @@ func testCompactWithStoreGateway(t *testing.T, penaltyDedup bool) { testutil.Ok(t, os.MkdirAll(dir, os.ModePerm)) const bucket = "compact_test" - m, err := e2ethanos.NewMinio(e, "minio", bucket) - testutil.Ok(t, err) + m := e2ethanos.NewMinio(e, "minio", bucket) testutil.Ok(t, e2e.StartAndWaitReady(m)) bkt, err := s3.NewBucketWithConfig(logger, @@ -452,19 +451,17 @@ func testCompactWithStoreGateway(t *testing.T, penaltyDedup bool) { svcConfig := client.BucketConfig{ Type: client.S3, - Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), e2ethanos.ContainerSharedDir), + Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), m.InternalDir()), } // Crank down the deletion mark delay since deduplication can miss blocks in the presence of replica labels it doesn't know about. - str, err := e2ethanos.NewStoreGW(e, "1", svcConfig, "", []string{"--ignore-deletion-marks-delay=2s"}) - testutil.Ok(t, err) + str := e2ethanos.NewStoreGW(e, "1", svcConfig, "", []string{"--ignore-deletion-marks-delay=2s"}) testutil.Ok(t, e2e.StartAndWaitReady(str)) testutil.Ok(t, str.WaitSumMetrics(e2e.Equals(float64(len(rawBlockIDs)+8)), "thanos_blocks_meta_synced")) testutil.Ok(t, str.WaitSumMetrics(e2e.Equals(0), "thanos_blocks_meta_sync_failures_total")) testutil.Ok(t, str.WaitSumMetrics(e2e.Equals(0), "thanos_blocks_meta_modified")) - q, err := e2ethanos.NewQuerierBuilder(e, "1", str.InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", str.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel = context.WithTimeout(context.Background(), 3*time.Minute) @@ -626,8 +623,7 @@ func testCompactWithStoreGateway(t *testing.T, penaltyDedup bool) { testutil.Ok(t, err) testutil.Ok(t, f.Close()) - c, err := e2ethanos.NewCompactor(e, "expect-to-halt", svcConfig, nil) - testutil.Ok(t, err) + c := e2ethanos.NewCompactor(e, "expect-to-halt", svcConfig, nil) testutil.Ok(t, e2e.StartAndWaitReady(c)) // Expect compactor halted and for one cleanup iteration to happen. @@ -690,8 +686,7 @@ func testCompactWithStoreGateway(t *testing.T, penaltyDedup bool) { } // We expect 2x 4-block compaction, 2-block vertical compaction, 2x 3-block compaction. - c, err := e2ethanos.NewCompactor(e, "working", svcConfig, nil, extArgs...) - testutil.Ok(t, err) + c := e2ethanos.NewCompactor(e, "working", svcConfig, nil, extArgs...) testutil.Ok(t, e2e.StartAndWaitReady(c)) // NOTE: We cannot assert on intermediate `thanos_blocks_meta_` metrics as those are gauge and change dynamically due to many @@ -760,8 +755,7 @@ func testCompactWithStoreGateway(t *testing.T, penaltyDedup bool) { if penaltyDedup { extArgs = append(extArgs, "--deduplication.func=penalty") } - c, err := e2ethanos.NewCompactor(e, "working-dedup", svcConfig, nil, extArgs...) - testutil.Ok(t, err) + c := e2ethanos.NewCompactor(e, "working-dedup", svcConfig, nil, extArgs...) testutil.Ok(t, e2e.StartAndWaitReady(c)) // NOTE: We cannot assert on intermediate `thanos_blocks_meta_` metrics as those are gauge and change dynamically due to many diff --git a/test/e2e/compatibility_test.go b/test/e2e/compatibility_test.go index 6b6c7e18fd..0fc114ef16 100644 --- a/test/e2e/compatibility_test.go +++ b/test/e2e/compatibility_test.go @@ -33,8 +33,7 @@ func TestPromQLCompliance(t *testing.T) { t.Cleanup(e.Close) // Start receive + Querier. - receiverRunnable, err := e2ethanos.NewIngestingReceiver(e, "receive") - testutil.Ok(t, err) + receiverRunnable := e2ethanos.NewIngestingReceiver(e, "receive") queryReceive := e2edb.NewThanosQuerier(e, "query_receive", []string{receiverRunnable.InternalEndpoint("grpc")}) testutil.Ok(t, e2e.StartAndWaitReady(receiverRunnable, queryReceive)) @@ -118,80 +117,73 @@ query_tweaks: }() } -// nolint (it's still used in skipped test). -type alwaysReadyProbe struct{} - -// nolint (it's still used in skipped test). -func (p alwaysReadyProbe) Ready(e2e.Runnable) error { return nil } - // TestAlertCompliance tests Alert compatibility against https://github.com/prometheus/compliance/blob/main/alert_generator. -// NOTE: This requires dockerization of compliance framework: https://github.com/prometheus/compliance/pull/46 -func TestAlertCompliance_StatelessRuler(t *testing.T) { - t.Skip("This is an interactive test, using https://github.com/prometheus/compliance/tree/main/alert_generator testing is not optimized for CI runs") - - e, err := e2e.NewDockerEnvironment("alert_compatibility") - testutil.Ok(t, err) - t.Cleanup(e.Close) - - // Start receive + Querier. - receive, err := e2ethanos.NewIngestingReceiver(e, "receive") - testutil.Ok(t, err) - query := e2edb.NewThanosQuerier(e, "query_receive", []string{receive.InternalEndpoint("grpc")}) - - compliance := e.Runnable("alert_generator_compliance_tester").WithPorts(map[string]int{"http": 8080}).Init(e2e.StartOptions{ - Image: "alert_generator_compliance_tester:latest", - // Batch job with HTTP port, we will start it with Exec, no need for readiness. - Readiness: alwaysReadyProbe{}, - Command: e2e.NewCommandWithoutEntrypoint("tail", "-f", "/dev/null"), - }) - ruler := e2ethanos.NewStatelessRuler(e, "1", "rules", []alert.AlertmanagerConfig{ - { - EndpointsConfig: httpconfig.EndpointsConfig{ - StaticAddresses: []string{compliance.InternalEndpoint("http")}, - Scheme: "http", +// NOTE: This requires a dockerization of compliance framework: https://github.com/prometheus/compliance/pull/46 +func TestAlertCompliance(t *testing.T) { + //t.Skip("This is an interactive test, using https://github.com/prometheus/compliance/tree/main/alert_generator. This tool is not optimized for CI runs (e.g. it infinitely retries") + + t.Run("staleness ruler", func(t *testing.T) { + e, err := e2e.NewDockerEnvironment("alert_compatibility") + testutil.Ok(t, err) + t.Cleanup(e.Close) + + // Start receive + Querier. + receive := e2ethanos.NewIngestingReceiver(e, "receive") + querierBuilder := e2ethanos.NewQuerierBuilder(e, "query", receive.InternalEndpoint("grpc")) + + compliance := e.Runnable("alert_generator_compliance_tester").WithPorts(map[string]int{"http": 8080}).Init(e2e.StartOptions{ + Image: "alert_generator_compliance_tester:latest", + Command: e2e.NewCommandRunUntilStop(), + }) + ruler := e2ethanos.NewStatelessRuler(e, "1", "rules", []alert.AlertmanagerConfig{ + { + EndpointsConfig: httpconfig.EndpointsConfig{ + StaticAddresses: []string{compliance.InternalEndpoint("http")}, + Scheme: "http", + }, + Timeout: amTimeout, + APIVersion: alert.APIv1, }, - Timeout: amTimeout, - APIVersion: alert.APIv1, - }, - }, []httpconfig.Config{ - { - EndpointsConfig: httpconfig.EndpointsConfig{ - StaticAddresses: []string{ - query.InternalEndpoint("http"), + }, []httpconfig.Config{ + { + EndpointsConfig: httpconfig.EndpointsConfig{ + StaticAddresses: []string{ + querierBuilder.Future().InternalEndpoint("http"), + }, + Scheme: "http", }, - Scheme: "http", }, - }, - }, []*config.RemoteWriteConfig{ - {URL: &common_cfg.URL{URL: urlParse(t, e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("remote-write")))}, Name: "thanos-receiver"}, - }) - testutil.Ok(t, e2e.StartAndWaitReady(receive, query, ruler, compliance)) + }, []*config.RemoteWriteConfig{ + {URL: &common_cfg.URL{URL: urlParse(t, e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("remote-write")))}, Name: "thanos-receiver"}, + }) + query := querierBuilder.WithRuleAddresses(ruler.InternalEndpoint("grpc")).Init() + testutil.Ok(t, e2e.StartAndWaitReady(receive, query, ruler, compliance)) - // Pull rules.yaml: - { - var stdout bytes.Buffer - testutil.Ok(t, compliance.Exec(e2e.NewCommand("cat", "/rules.yaml"), e2e.WithExecOptionStdout(&stdout))) - testutil.Ok(t, os.MkdirAll(filepath.Join(ruler.Dir(), "rules"), os.ModePerm)) - testutil.Ok(t, os.WriteFile(filepath.Join(ruler.Dir(), "rules", "rules.yaml"), stdout.Bytes(), os.ModePerm)) - } + // Pull rules.yaml: + { + var stdout bytes.Buffer + testutil.Ok(t, compliance.Exec(e2e.NewCommand("cat", "/rules.yaml"), e2e.WithExecOptionStdout(&stdout))) + testutil.Ok(t, os.MkdirAll(filepath.Join(ruler.Dir(), "rules"), os.ModePerm)) + testutil.Ok(t, os.WriteFile(filepath.Join(ruler.Dir(), "rules", "rules.yaml"), stdout.Bytes(), os.ModePerm)) + } - testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "test-thanos.yaml"), - []byte(alertCompatConfig(receive, query)), os.ModePerm)) + testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "test-thanos.yaml"), []byte(alertCompatConfig(receive, query)), os.ModePerm)) - fmt.Println(alertCompatConfig(receive, query)) + fmt.Println(alertCompatConfig(receive, query)) - testutil.Ok(t, compliance.Exec(e2e.NewCommand( - "/alert_generator_compliance_tester", "-config-file", filepath.Join(compliance.InternalDir(), "test-thanos.yaml")), - )) + testutil.Ok(t, compliance.Exec(e2e.NewCommand( + "/alert_generator_compliance_tester", "-config-file", filepath.Join(compliance.InternalDir(), "test-thanos.yaml")), + )) + }) } // nolint (it's still used in skipped test). func alertCompatConfig(receive e2e.Runnable, query e2e.Runnable) string { - return `settings: - remote_write_url: '` + e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("http")) + `' - query_base_url: 'http://` + query.InternalEndpoint("http") + `' - rules_and_alerts_api_base_url: 'http://` + query.InternalEndpoint("http") + `' + return fmt.Sprintf(`settings: + remote_write_url: '%s' + query_base_url: 'http://%s' + rules_and_alerts_api_base_url: 'http://%s' alert_reception_server_port: 8080 alert_message_parser: default -` +`, e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("http")), query.InternalEndpoint("http"), query.InternalEndpoint("http")) } diff --git a/test/e2e/e2ethanos/service.go b/test/e2e/e2ethanos/service.go deleted file mode 100644 index 0db089391e..0000000000 --- a/test/e2e/e2ethanos/service.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) The Thanos Authors. -// Licensed under the Apache License 2.0. - -package e2ethanos - -import ( - "os" - "strconv" - - "github.com/efficientgo/e2e" -) - -type Port struct { - Name string - PortNum int - IsMetrics bool -} - -func NewService( - e e2e.Environment, - name string, - image string, - command e2e.Command, - readiness *e2e.HTTPReadinessProbe, - http, grpc int, - otherPorts ...Port, -) e2e.InstrumentedRunnable { - return newUninitiatedService(e, name, http, grpc, otherPorts...).Init( - e2e.StartOptions{ - Image: image, - Command: command, - Readiness: readiness, - User: strconv.Itoa(os.Getuid()), - WaitReadyBackoff: &defaultBackoffConfig, - }, - ) -} - -func newUninitiatedService( - e e2e.Environment, - name string, - http, grpc int, - otherPorts ...Port, -) e2e.InstrumentedRunnableBuilder { - metricsPorts := "http" - ports := map[string]int{ - "http": http, - "grpc": grpc, - } - - for _, op := range otherPorts { - ports[op.Name] = op.PortNum - - if op.IsMetrics { - metricsPorts = op.Name - } - } - - return e2e.NewInstrumentedRunnable(e, name).WithPorts(ports, metricsPorts) -} - -func initiateService( - service e2e.InstrumentedRunnableBuilder, - image string, - command e2e.Command, - readiness *e2e.HTTPReadinessProbe, -) e2e.InstrumentedRunnable { - return service.Init( - e2e.StartOptions{ - Image: image, - Command: command, - Readiness: readiness, - User: strconv.Itoa(os.Getuid()), - WaitReadyBackoff: &defaultBackoffConfig, - }, - ) -} diff --git a/test/e2e/e2ethanos/services.go b/test/e2e/e2ethanos/services.go index c642db321e..4461aca0a1 100644 --- a/test/e2e/e2ethanos/services.go +++ b/test/e2e/e2ethanos/services.go @@ -39,8 +39,7 @@ import ( ) const ( - infoLogLevel = "info" - ContainerSharedDir = "/shared" + infoLogLevel = "info" ) // Same as default for now. @@ -50,15 +49,28 @@ var defaultBackoffConfig = backoff.Config{ MaxRetries: 50, } +// TODO(bwplotka): Make strconv.Itoa(os.Getuid()) pattern in e2e? +func wrapWithDefaults(opt e2e.StartOptions) e2e.StartOptions { + if opt.User == "" { + opt.User = strconv.Itoa(os.Getuid()) + } + if opt.WaitReadyBackoff == nil { + opt.WaitReadyBackoff = &defaultBackoffConfig + } + return opt +} + const ( + // FeatureExemplarStorage is a feature flag that enables exemplar storage on Prometheus. FeatureExemplarStorage = "exemplar-storage" ) -// TODO(bwplotka): Run against multiple? +// DefaultPrometheusImage sets default Prometheus image used in e2e service. func DefaultPrometheusImage() string { return "quay.io/prometheus/prometheus:v2.29.2" } +// DefaultAlertmanagerImage sets default Alertmanager image used in e2e service. func DefaultAlertmanagerImage() string { return "quay.io/prometheus/alertmanager:v0.20.0" } @@ -81,28 +93,27 @@ func defaultPromHttpConfig() string { ` } -func NewPrometheus(e e2e.Environment, name, promConfig, webConfig, promImage string, enableFeatures ...string) (e2e.InstrumentedRunnable, string, error) { - dir := filepath.Join(e.SharedDir(), "data", "prometheus", name) - container := filepath.Join(ContainerSharedDir, "data", "prometheus", name) - if err := os.MkdirAll(dir, 0750); err != nil { - return nil, "", errors.Wrap(err, "create prometheus dir") +func NewPrometheus(e e2e.Environment, name, promConfig, webConfig, promImage string, enableFeatures ...string) e2e.InstrumentedRunnable { + f := e2e.NewInstrumentedRunnable(e, name).WithPorts(map[string]int{"http": 9090}, "http").Future() + + if err := os.MkdirAll(f.Dir(), 0750); err != nil { + return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "create prometheus dir")) } - if err := ioutil.WriteFile(filepath.Join(dir, "prometheus.yml"), []byte(promConfig), 0600); err != nil { - return nil, "", errors.Wrap(err, "creating prom config failed") + if err := ioutil.WriteFile(filepath.Join(f.Dir(), "prometheus.yml"), []byte(promConfig), 0600); err != nil { + return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "creating prom config")) } if len(webConfig) > 0 { - if err := ioutil.WriteFile(filepath.Join(dir, "web-config.yml"), []byte(webConfig), 0600); err != nil { - return nil, "", errors.Wrap(err, "creating web-config failed") + if err := ioutil.WriteFile(filepath.Join(f.Dir(), "web-config.yml"), []byte(webConfig), 0600); err != nil { + return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "creating web-config")) } } probe := e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200) - args := e2e.BuildArgs(map[string]string{ - "--config.file": filepath.Join(container, "prometheus.yml"), - "--storage.tsdb.path": container, + "--config.file": filepath.Join(f.InternalDir(), "prometheus.yml"), + "--storage.tsdb.path": f.InternalDir(), "--storage.tsdb.max-block-duration": "2h", "--log.level": infoLogLevel, "--web.listen-address": ":9090", @@ -112,38 +123,23 @@ func NewPrometheus(e e2e.Environment, name, promConfig, webConfig, promImage str args = append(args, fmt.Sprintf("--enable-feature=%s", strings.Join(enableFeatures, ","))) } if len(webConfig) > 0 { - args = append(args, fmt.Sprintf("--web.config.file=%s", filepath.Join(container, "web-config.yml"))) + args = append(args, fmt.Sprintf("--web.config.file=%s", filepath.Join(f.InternalDir(), "web-config.yml"))) // If auth is enabled then prober would get 401 error. probe = e2e.NewHTTPReadinessProbe("http", "/-/ready", 401, 401) } - prom := e2e.NewInstrumentedRunnable( - e, - fmt.Sprintf("prometheus-%s", name), - ).WithPorts( - map[string]int{"http": 9090}, - "http", - ).Init( - e2e.StartOptions{ - Image: promImage, - Command: e2e.NewCommandWithoutEntrypoint("prometheus", args...), - Readiness: probe, - User: strconv.Itoa(os.Getuid()), - WaitReadyBackoff: &defaultBackoffConfig, - }, - ) - - return prom, container, nil + return f.Init(wrapWithDefaults(e2e.StartOptions{ + Image: promImage, + Command: e2e.NewCommandWithoutEntrypoint("prometheus", args...), + Readiness: probe, + })) } -func NewPrometheusWithSidecar(e e2e.Environment, name, promConfig, webConfig, promImage, minTime string, enableFeatures ...string) (e2e.InstrumentedRunnable, e2e.InstrumentedRunnable, error) { +func NewPrometheusWithSidecar(e e2e.Environment, name, promConfig, webConfig, promImage, minTime string, enableFeatures ...string) (e2e.InstrumentedRunnable, e2e.InstrumentedRunnable) { return NewPrometheusWithSidecarCustomImage(e, name, promConfig, webConfig, promImage, minTime, DefaultImage(), enableFeatures...) } -func NewPrometheusWithSidecarCustomImage(e e2e.Environment, name, promConfig, webConfig, promImage, minTime string, sidecarImage string, enableFeatures ...string) (e2e.InstrumentedRunnable, e2e.InstrumentedRunnable, error) { - prom, dataDir, err := NewPrometheus(e, name, promConfig, webConfig, promImage, enableFeatures...) - if err != nil { - return nil, nil, err - } +func NewPrometheusWithSidecarCustomImage(e e2e.Environment, name, promConfig, webConfig, promImage, minTime string, sidecarImage string, enableFeatures ...string) (e2e.InstrumentedRunnable, e2e.InstrumentedRunnable) { + prom := NewPrometheus(e, name, promConfig, webConfig, promImage, enableFeatures...) args := map[string]string{ "--debug.name": fmt.Sprintf("sidecar-%v", name), @@ -151,7 +147,7 @@ func NewPrometheusWithSidecarCustomImage(e e2e.Environment, name, promConfig, we "--grpc-grace-period": "0s", "--http-address": ":8080", "--prometheus.url": "http://" + prom.InternalEndpoint("http"), - "--tsdb.path": dataDir, + "--tsdb.path": prom.InternalDir(), "--log.level": "debug", } if len(webConfig) > 0 { @@ -160,17 +156,14 @@ func NewPrometheusWithSidecarCustomImage(e e2e.Environment, name, promConfig, we if minTime != "" { args["--min-time"] = minTime } - sidecar := NewService( - e, - fmt.Sprintf("sidecar-%s", name), - sidecarImage, - e2e.NewCommand("sidecar", e2e.BuildArgs(args)...), - e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), - 8080, - 9091, - ) - - return prom, sidecar, nil + sidecar := e2e.NewInstrumentedRunnable(e, fmt.Sprintf("sidecar-%s", name)). + WithPorts(map[string]int{"http": 8080, "grpc": 9091}, "http"). + Init(wrapWithDefaults(e2e.StartOptions{ + Image: sidecarImage, + Command: e2e.NewCommand("sidecar", e2e.BuildArgs(args)...), + Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), + })) + return prom, sidecar } type QuerierBuilder struct { @@ -191,6 +184,8 @@ type QuerierBuilder struct { endpoints []string tracingConfig string + + f e2e.FutureInstrumentedRunnable } func NewQuerierBuilder(e e2e.Environment, name string, storeAddresses ...string) *QuerierBuilder { @@ -213,6 +208,11 @@ func (q *QuerierBuilder) WithImage(image string) *QuerierBuilder { return q } +func (q *QuerierBuilder) WithStoreAddresses(storeAddresses ...string) *QuerierBuilder { + q.storeAddresses = storeAddresses + return q +} + func (q *QuerierBuilder) WithFileSDStoreAddresses(fileSDStoreAddresses ...string) *QuerierBuilder { q.fileSDStoreAddresses = fileSDStoreAddresses return q @@ -258,52 +258,33 @@ func (q *QuerierBuilder) WithTracingConfig(tracingConfig string) *QuerierBuilder return q } -func (q *QuerierBuilder) BuildUninitiated() e2e.InstrumentedRunnableBuilder { - return newUninitiatedService( - q.environment, - fmt.Sprintf("querier-%v", q.name), - 8080, - 9091, - ) -} - -func (q *QuerierBuilder) Initiate(service e2e.InstrumentedRunnableBuilder, storeAddresses ...string) (e2e.InstrumentedRunnable, error) { - q.storeAddresses = storeAddresses - args, err := q.collectArgs() - if err != nil { - return nil, err +func (q *QuerierBuilder) Future() e2e.FutureInstrumentedRunnable { + if q.f != nil { + return q.f } - - querier := initiateService( - service, - q.image, - e2e.NewCommand("query", args...), - e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), - ) - - return querier, nil + q.f = e2e.NewInstrumentedRunnable(q.environment, fmt.Sprintf("querier-%v", q.name)). + WithPorts(map[string]int{ + "http": 8080, + "grpc": 9091, + }, "http"). + Future() + return q.f } -func (q *QuerierBuilder) Build() (e2e.InstrumentedRunnable, error) { - args, err := q.collectArgs() +func (q *QuerierBuilder) Init() e2e.InstrumentedRunnable { + args, err := q.collectArgs(q.Future()) if err != nil { - return nil, err + return e2e.NewErrInstrumentedRunnable(q.name, err) } - querier := NewService( - q.environment, - fmt.Sprintf("querier-%v", q.name), - q.image, - e2e.NewCommand("query", args...), - e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), - 8080, - 9091, - ) - - return querier, nil + return q.f.Init(wrapWithDefaults(e2e.StartOptions{ + Image: q.image, + Command: e2e.NewCommand("query", args...), + Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), + })) } -func (q *QuerierBuilder) collectArgs() ([]string, error) { +func (q *QuerierBuilder) collectArgs(f e2e.FutureInstrumentedRunnable) ([]string, error) { const replicaLabel = "replica" args := e2e.BuildArgs(map[string]string{ @@ -346,9 +327,7 @@ func (q *QuerierBuilder) collectArgs() ([]string, error) { } if len(q.fileSDStoreAddresses) > 0 { - queryFileSDDir := filepath.Join(q.sharedDir, "data", "querier", q.name) - container := filepath.Join(ContainerSharedDir, "data", "querier", q.name) - if err := os.MkdirAll(queryFileSDDir, 0750); err != nil { + if err := os.MkdirAll(f.Dir(), 0750); err != nil { return nil, errors.Wrap(err, "create query dir failed") } @@ -362,11 +341,11 @@ func (q *QuerierBuilder) collectArgs() ([]string, error) { return nil, err } - if err := ioutil.WriteFile(queryFileSDDir+"/filesd.yaml", b, 0600); err != nil { + if err := ioutil.WriteFile(f.Dir()+"/filesd.yaml", b, 0600); err != nil { return nil, errors.Wrap(err, "creating query SD config failed") } - args = append(args, "--store.sd-files="+filepath.Join(container, "filesd.yaml")) + args = append(args, "--store.sd-files="+filepath.Join(f.InternalDir(), "filesd.yaml")) } if q.routePrefix != "" { @@ -386,178 +365,114 @@ func (q *QuerierBuilder) collectArgs() ([]string, error) { func RemoteWriteEndpoint(addr string) string { return fmt.Sprintf("http://%s/api/v1/receive", addr) } -// NewUninitiatedReceiver returns a future receiver that can be initiated. It is useful +// NewFutureReceiver returns a future receiver that can be initiated. It is useful // for obtaining a receiver address for hashring before the receiver is started. -func NewUninitiatedReceiver(e e2e.Environment, name string) e2e.InstrumentedRunnableBuilder { - return newUninitiatedService(e, fmt.Sprintf("receive-%v", name), 8080, 9091, Port{Name: "remote-write", PortNum: 8081}) +func NewFutureReceiver(e e2e.Environment, name string) e2e.FutureInstrumentedRunnable { + return e2e.NewInstrumentedRunnable(e, fmt.Sprintf("receive-%v", name)). + WithPorts(map[string]int{"http": 8080, "grpc": 9091, "remote-write": 8081}, "http"). + Future() } -// NewRoutingAndIngestingReceiverFromService creates a Thanos Receive instances from an unitiated service. +// NewRoutingAndIngestingReceiverFromFuture creates a Thanos Receive instances from a future service. // It is configured both for ingesting samples and routing samples to other receivers. -func NewRoutingAndIngestingReceiverFromService(service e2e.InstrumentedRunnableBuilder, sharedDir string, replicationFactor int, hashring ...receive.HashringConfig) (e2e.InstrumentedRunnable, error) { +func NewRoutingAndIngestingReceiverFromFuture(f e2e.FutureInstrumentedRunnable, replicationFactor int, hashring ...receive.HashringConfig) e2e.InstrumentedRunnable { var localEndpoint string if len(hashring) == 0 { localEndpoint = "0.0.0.0:9091" hashring = []receive.HashringConfig{{Endpoints: []string{localEndpoint}}} } else { - localEndpoint = service.Future().InternalEndpoint("grpc") + localEndpoint = f.InternalEndpoint("grpc") } - dir := filepath.Join(sharedDir, "data", "receive", service.Future().Name()) - dataDir := filepath.Join(dir, "data") - container := filepath.Join(ContainerSharedDir, "data", "receive", service.Future().Name()) - if err := os.MkdirAll(dataDir, 0750); err != nil { - return nil, errors.Wrap(err, "create receive dir") + if err := os.MkdirAll(filepath.Join(f.Dir(), "data"), 0750); err != nil { + return e2e.NewErrInstrumentedRunnable(f.Name(), errors.Wrap(err, "create receive dir")) } b, err := json.Marshal(hashring) if err != nil { - return nil, errors.Wrapf(err, "generate hashring file: %v", hashring) + return e2e.NewErrInstrumentedRunnable(f.Name(), errors.Wrapf(err, "generate hashring file: %v", hashring)) } - receiver := initiateService( - service, - DefaultImage(), - // TODO(bwplotka): BuildArgs should be interface. - e2e.NewCommand("receive", e2e.BuildArgs(map[string]string{ - "--debug.name": service.Future().Name(), - "--grpc-address": ":9091", - "--grpc-grace-period": "0s", - "--http-address": ":8080", - "--remote-write.address": ":8081", - "--label": fmt.Sprintf(`receive="%s"`, service.Future().Name()), - "--tsdb.path": filepath.Join(container, "data"), - "--log.level": infoLogLevel, - "--receive.replication-factor": strconv.Itoa(replicationFactor), - "--receive.local-endpoint": localEndpoint, - "--receive.hashrings": string(b), - })...), - e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), - ) - - return receiver, nil -} - -func NewRoutingAndIngestingReceiverWithConfigWatcher(service e2e.InstrumentedRunnableBuilder, sharedDir string, replicationFactor int, hashring ...receive.HashringConfig) (e2e.InstrumentedRunnable, error) { - var localEndpoint string - if len(hashring) == 0 { - localEndpoint = "0.0.0.0:9091" - hashring = []receive.HashringConfig{{Endpoints: []string{localEndpoint}}} - } else { - localEndpoint = service.Future().InternalEndpoint("grpc") + if err := ioutil.WriteFile(filepath.Join(f.Dir(), "hashrings.json"), b, 0600); err != nil { + return e2e.NewErrInstrumentedRunnable(f.Name(), errors.Wrap(err, "creating receive config")) } - dir := filepath.Join(sharedDir, "data", "receive", service.Future().Name()) - dataDir := filepath.Join(dir, "data") - container := filepath.Join(ContainerSharedDir, "data", "receive", service.Future().Name()) - if err := os.MkdirAll(dataDir, 0750); err != nil { - return nil, errors.Wrap(err, "create receive dir") - } - b, err := json.Marshal(hashring) - if err != nil { - return nil, errors.Wrapf(err, "generate hashring file: %v", hashring) - } - - if err := ioutil.WriteFile(filepath.Join(dir, "hashrings.json"), b, 0600); err != nil { - return nil, errors.Wrap(err, "creating receive config") - } - - receiver := initiateService( - service, - DefaultImage(), - // TODO(bwplotka): BuildArgs should be interface. + return f.Init(wrapWithDefaults(e2e.StartOptions{ + Image: DefaultImage(), + Command: // TODO(bwplotka): BuildArgs should be interface. e2e.NewCommand("receive", e2e.BuildArgs(map[string]string{ - "--debug.name": service.Future().Name(), + "--debug.name": f.Name(), "--grpc-address": ":9091", "--grpc-grace-period": "0s", "--http-address": ":8080", "--remote-write.address": ":8081", - "--label": fmt.Sprintf(`receive="%s"`, service.Future().Name()), - "--tsdb.path": filepath.Join(container, "data"), + "--label": fmt.Sprintf(`receive="%s"`, f.Name()), + "--tsdb.path": filepath.Join(f.InternalDir(), "data"), "--log.level": infoLogLevel, "--receive.replication-factor": strconv.Itoa(replicationFactor), "--receive.local-endpoint": localEndpoint, - "--receive.hashrings-file": filepath.Join(container, "hashrings.json"), + "--receive.hashrings-file": filepath.Join(f.InternalDir(), "hashrings.json"), "--receive.hashrings-file-refresh-interval": "5s", })...), - e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), - ) - - return receiver, nil + Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), + })) } // NewRoutingReceiver creates a Thanos Receive instance that is only configured to route to other receive instances. It has no local storage. -func NewRoutingReceiver(e e2e.Environment, name string, replicationFactor int, hashring ...receive.HashringConfig) (e2e.InstrumentedRunnable, error) { - +func NewRoutingReceiver(e e2e.Environment, name string, replicationFactor int, hashring ...receive.HashringConfig) e2e.InstrumentedRunnable { if len(hashring) == 0 { - return nil, errors.New("hashring should not be empty for receive-distributor mode") + return e2e.NewErrInstrumentedRunnable(name, errors.New("hashring should not be empty for receive-distributor mode")) } - dir := filepath.Join(e.SharedDir(), "data", "receive", name) - dataDir := filepath.Join(dir, "data") - container := filepath.Join(ContainerSharedDir, "data", "receive", name) - if err := os.MkdirAll(dataDir, 0750); err != nil { - return nil, errors.Wrap(err, "create receive dir") + f := NewFutureReceiver(e, name) + if err := os.MkdirAll(f.Dir(), 0750); err != nil { + return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "create receive dir")) } b, err := json.Marshal(hashring) if err != nil { - return nil, errors.Wrapf(err, "generate hashring file: %v", hashring) + e2e.NewErrInstrumentedRunnable(name, errors.Wrapf(err, "generate hashring file: %v", hashring)) } - receiver := NewService( - e, - fmt.Sprintf("receive-%v", name), - DefaultImage(), + return f.Init(wrapWithDefaults(e2e.StartOptions{ + Image: DefaultImage(), // TODO(bwplotka): BuildArgs should be interface. - e2e.NewCommand("receive", e2e.BuildArgs(map[string]string{ + Command: e2e.NewCommand("receive", e2e.BuildArgs(map[string]string{ "--debug.name": fmt.Sprintf("receive-%v", name), "--grpc-address": ":9091", "--grpc-grace-period": "0s", "--http-address": ":8080", "--remote-write.address": ":8081", "--label": fmt.Sprintf(`receive="%s"`, name), - "--tsdb.path": filepath.Join(container, "data"), + "--tsdb.path": filepath.Join(f.InternalDir(), "data"), "--log.level": infoLogLevel, "--receive.replication-factor": strconv.Itoa(replicationFactor), "--receive.hashrings": string(b), })...), - e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), - 8080, - 9091, - Port{Name: "remote-write", PortNum: 8081}, - ) - - return receiver, nil + Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), + })) } // NewIngestingReceiver creates a Thanos Receive instance that is only configured to ingest, not route to other receivers. -func NewIngestingReceiver(e e2e.Environment, name string) (e2e.InstrumentedRunnable, error) { - dir := filepath.Join(e.SharedDir(), "data", "receive", name) - dataDir := filepath.Join(dir, "data") - container := filepath.Join(ContainerSharedDir, "data", "receive", name) - if err := os.MkdirAll(dataDir, 0750); err != nil { - return nil, errors.Wrap(err, "create receive dir") - } - receiver := NewService(e, - fmt.Sprintf("receive-%v", name), - DefaultImage(), +func NewIngestingReceiver(e e2e.Environment, name string) e2e.InstrumentedRunnable { + f := NewFutureReceiver(e, name) + if err := os.MkdirAll(f.Dir(), 0750); err != nil { + return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "create receive dir")) + } + + return f.Init(wrapWithDefaults(e2e.StartOptions{ + Image: DefaultImage(), // TODO(bwplotka): BuildArgs should be interface. - e2e.NewCommand("receive", e2e.BuildArgs(map[string]string{ + Command: e2e.NewCommand("receive", e2e.BuildArgs(map[string]string{ "--debug.name": fmt.Sprintf("receive-%v", name), "--grpc-address": ":9091", "--grpc-grace-period": "0s", "--http-address": ":8080", "--remote-write.address": ":8081", "--label": fmt.Sprintf(`receive="%s"`, name), - "--tsdb.path": filepath.Join(container, "data"), + "--tsdb.path": filepath.Join(f.InternalDir(), "data"), "--log.level": infoLogLevel, })...), - e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), - 8080, - 9091, - Port{Name: "remote-write", PortNum: 8081}, - ) - - return receiver, nil + Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), + })) } func NewTSDBRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config) e2e.InstrumentedRunnable { @@ -569,10 +484,11 @@ func NewStatelessRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert } func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig) e2e.InstrumentedRunnable { - dir := filepath.Join(e.SharedDir(), "data", "rule", name) - container := filepath.Join(ContainerSharedDir, "data", "rule", name) + f := e2e.NewInstrumentedRunnable(e, fmt.Sprintf("rule-%v", name)). + WithPorts(map[string]int{"http": 8080, "grpc": 9091}, "http"). + Future() - if err := os.MkdirAll(dir, 0750); err != nil { + if err := os.MkdirAll(f.Dir(), 0750); err != nil { return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "create rule dir")) } @@ -594,8 +510,8 @@ func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.Alertman "--grpc-grace-period": "0s", "--http-address": ":8080", "--label": fmt.Sprintf(`replica="%s"`, name), - "--data-dir": container, - "--rule-file": filepath.Join(ContainerSharedDir, ruleSubDir, "*.yaml"), + "--data-dir": f.InternalDir(), + "--rule-file": filepath.Join(f.InternalDir(), ruleSubDir, "*.yaml"), "--eval-interval": "1s", "--alertmanagers.config": string(amCfgBytes), "--alertmanagers.sd-dns-interval": "1s", @@ -614,22 +530,20 @@ func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.Alertman ruleArgs["--remote-write.config"] = string(rwCfgBytes) } - return NewService(e, - fmt.Sprintf("rule-%v", name), - DefaultImage(), - e2e.NewCommand("rule", e2e.BuildArgs(ruleArgs)...), - e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), - 8080, - 9091, - ) - + return f.Init(wrapWithDefaults(e2e.StartOptions{ + Image: DefaultImage(), + Command: e2e.NewCommand("rule", e2e.BuildArgs(ruleArgs)...), + Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), + })) } -func NewAlertmanager(e e2e.Environment, name string) (e2e.InstrumentedRunnable, error) { - dir := filepath.Join(e.SharedDir(), "data", "am", name) - container := filepath.Join(ContainerSharedDir, "data", "am", name) - if err := os.MkdirAll(dir, 0750); err != nil { - return nil, errors.Wrap(err, "create am dir") +func NewAlertmanager(e e2e.Environment, name string) e2e.InstrumentedRunnable { + f := e2e.NewInstrumentedRunnable(e, fmt.Sprintf("alertmanager-%v", name)). + WithPorts(map[string]int{"http": 8080}, "http"). + Future() + + if err := os.MkdirAll(f.Dir(), 0750); err != nil { + return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "create am dir")) } const config = ` route: @@ -640,50 +554,43 @@ route: receivers: - name: 'null' ` - if err := ioutil.WriteFile(filepath.Join(dir, "config.yaml"), []byte(config), 0600); err != nil { - return nil, errors.Wrap(err, "creating alertmanager config file failed") - } - - s := e2e.NewInstrumentedRunnable( - e, fmt.Sprintf("alertmanager-%v", name), - ).WithPorts( - map[string]int{"http": 8080}, - "http", - ).Init( - e2e.StartOptions{ - Image: DefaultAlertmanagerImage(), - Command: e2e.NewCommandWithoutEntrypoint("/bin/alertmanager", e2e.BuildArgs(map[string]string{ - "--config.file": filepath.Join(container, "config.yaml"), - "--web.listen-address": "0.0.0.0:8080", - "--log.level": infoLogLevel, - "--storage.path": container, - "--web.get-concurrency": "1", - "--web.timeout": "2m", - })...), - Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), - User: strconv.Itoa(os.Geteuid()), - WaitReadyBackoff: &defaultBackoffConfig, - }, - ) - - return s, nil + if err := ioutil.WriteFile(filepath.Join(f.Dir(), "config.yaml"), []byte(config), 0600); err != nil { + return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "creating alertmanager config file failed")) + } + + return f.Init(wrapWithDefaults(e2e.StartOptions{ + Image: DefaultAlertmanagerImage(), + Command: e2e.NewCommandWithoutEntrypoint("/bin/alertmanager", e2e.BuildArgs(map[string]string{ + "--config.file": filepath.Join(f.InternalDir(), "config.yaml"), + "--web.listen-address": "0.0.0.0:8080", + "--log.level": infoLogLevel, + "--storage.path": f.InternalDir(), + "--web.get-concurrency": "1", + "--web.timeout": "2m", + })...), + Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), + User: strconv.Itoa(os.Geteuid()), + WaitReadyBackoff: &defaultBackoffConfig, + })) } -func NewStoreGW(e e2e.Environment, name string, bucketConfig client.BucketConfig, cacheConfig string, extArgs []string, relabelConfig ...relabel.Config) (e2e.InstrumentedRunnable, error) { - dir := filepath.Join(e.SharedDir(), "data", "store", name) - container := filepath.Join(ContainerSharedDir, "data", "store", name) - if err := os.MkdirAll(dir, 0750); err != nil { - return nil, errors.Wrap(err, "create store dir") +func NewStoreGW(e e2e.Environment, name string, bucketConfig client.BucketConfig, cacheConfig string, extArgs []string, relabelConfig ...relabel.Config) e2e.InstrumentedRunnable { + f := e2e.NewInstrumentedRunnable(e, fmt.Sprintf("store-gw-%v", name)). + WithPorts(map[string]int{"http": 8080, "grpc": 9091}, "http"). + Future() + + if err := os.MkdirAll(f.InternalDir(), 0750); err != nil { + return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "create store dir")) } bktConfigBytes, err := yaml.Marshal(bucketConfig) if err != nil { - return nil, errors.Wrapf(err, "generate store config file: %v", bucketConfig) + return e2e.NewErrInstrumentedRunnable(name, errors.Wrapf(err, "generate store config file: %v", bucketConfig)) } relabelConfigBytes, err := yaml.Marshal(relabelConfig) if err != nil { - return nil, errors.Wrapf(err, "generate store relabel file: %v", relabelConfig) + return e2e.NewErrInstrumentedRunnable(name, errors.Wrapf(err, "generate store relabel file: %v", relabelConfig)) } args := append(e2e.BuildArgs(map[string]string{ @@ -692,7 +599,7 @@ func NewStoreGW(e e2e.Environment, name string, bucketConfig client.BucketConfig "--grpc-grace-period": "0s", "--http-address": ":8080", "--log.level": infoLogLevel, - "--data-dir": container, + "--data-dir": f.InternalDir(), "--objstore.config": string(bktConfigBytes), // Accelerated sync time for quicker test (3m by default). "--sync-block-duration": "3s", @@ -706,68 +613,53 @@ func NewStoreGW(e e2e.Environment, name string, bucketConfig client.BucketConfig args = append(args, "--store.caching-bucket.config", cacheConfig) } - store := NewService( - e, - fmt.Sprintf("store-gw-%v", name), - DefaultImage(), - e2e.NewCommand("store", args...), - e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), - 8080, - 9091, - ) - - return store, nil + return f.Init(wrapWithDefaults(e2e.StartOptions{ + Image: DefaultImage(), + Command: e2e.NewCommand("store", args...), + Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), + })) } -func NewCompactor(e e2e.Environment, name string, bucketConfig client.BucketConfig, relabelConfig []relabel.Config, extArgs ...string) (e2e.InstrumentedRunnable, error) { - dir := filepath.Join(e.SharedDir(), "data", "compact", name) - container := filepath.Join(ContainerSharedDir, "data", "compact", name) +func NewCompactor(e e2e.Environment, name string, bucketConfig client.BucketConfig, relabelConfig []relabel.Config, extArgs ...string) e2e.InstrumentedRunnable { + f := e2e.NewInstrumentedRunnable(e, fmt.Sprintf("compact-%s", name)). + WithPorts(map[string]int{"http": 8080}, "http"). + Future() - if err := os.MkdirAll(dir, 0750); err != nil { - return nil, errors.Wrap(err, "create compact dir") + if err := os.MkdirAll(f.Dir(), 0750); err != nil { + return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "create compact dir")) } bktConfigBytes, err := yaml.Marshal(bucketConfig) if err != nil { - return nil, errors.Wrapf(err, "generate compact config file: %v", bucketConfig) + return e2e.NewErrInstrumentedRunnable(name, errors.Wrapf(err, "generate compact config file: %v", bucketConfig)) } relabelConfigBytes, err := yaml.Marshal(relabelConfig) if err != nil { - return nil, errors.Wrapf(err, "generate compact relabel file: %v", relabelConfig) - } - - compactor := e2e.NewInstrumentedRunnable( - e, fmt.Sprintf("compact-%s", name), - ).WithPorts( - map[string]int{"http": 8080}, "http", - ).Init( - e2e.StartOptions{ - Image: DefaultImage(), - Command: e2e.NewCommand("compact", append(e2e.BuildArgs(map[string]string{ - "--debug.name": fmt.Sprintf("compact-%s", name), - "--log.level": infoLogLevel, - "--data-dir": container, - "--objstore.config": string(bktConfigBytes), - "--http-address": ":8080", - "--block-sync-concurrency": "50", - "--compact.cleanup-interval": "15s", - "--selector.relabel-config": string(relabelConfigBytes), - "--wait": "", - }), extArgs...)...), - Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), - User: strconv.Itoa(os.Getuid()), - WaitReadyBackoff: &defaultBackoffConfig, - }, - ) - - return compactor, nil -} - -func NewQueryFrontend(e e2e.Environment, name, downstreamURL string, cacheConfig queryfrontend.CacheProviderConfig) (e2e.InstrumentedRunnable, error) { + return e2e.NewErrInstrumentedRunnable(name, errors.Wrapf(err, "generate compact relabel file: %v", relabelConfig)) + } + + return f.Init(wrapWithDefaults(e2e.StartOptions{ + Image: DefaultImage(), + Command: e2e.NewCommand("compact", append(e2e.BuildArgs(map[string]string{ + "--debug.name": fmt.Sprintf("compact-%s", name), + "--log.level": infoLogLevel, + "--data-dir": f.InternalDir(), + "--objstore.config": string(bktConfigBytes), + "--http-address": ":8080", + "--block-sync-concurrency": "50", + "--compact.cleanup-interval": "15s", + "--selector.relabel-config": string(relabelConfigBytes), + "--wait": "", + }), extArgs...)...), + Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), + })) +} + +func NewQueryFrontend(e e2e.Environment, name, downstreamURL string, cacheConfig queryfrontend.CacheProviderConfig) e2e.InstrumentedRunnable { cacheConfigBytes, err := yaml.Marshal(cacheConfig) if err != nil { - return nil, errors.Wrapf(err, "marshal response cache config file: %v", cacheConfig) + return e2e.NewErrInstrumentedRunnable(name, errors.Wrapf(err, "marshal response cache config file: %v", cacheConfig)) } args := e2e.BuildArgs(map[string]string{ @@ -778,7 +670,7 @@ func NewQueryFrontend(e e2e.Environment, name, downstreamURL string, cacheConfig "--query-range.response-cache-config": string(cacheConfigBytes), }) - queryFrontend := e2e.NewInstrumentedRunnable( + return e2e.NewInstrumentedRunnable( e, fmt.Sprintf("query-frontend-%s", name), ).WithPorts(map[string]int{"http": 8080}, "http").Init( e2e.StartOptions{ @@ -789,11 +681,9 @@ func NewQueryFrontend(e e2e.Environment, name, downstreamURL string, cacheConfig WaitReadyBackoff: &defaultBackoffConfig, }, ) - - return queryFrontend, nil } -func NewReverseProxy(e e2e.Environment, name, tenantID, target string) (e2e.InstrumentedRunnable, error) { +func NewReverseProxy(e e2e.Environment, name, tenantID, target string) e2e.InstrumentedRunnable { conf := fmt.Sprintf(` events { worker_connections 1024; @@ -812,30 +702,31 @@ http { } `, tenantID, target) - dir := filepath.Join(e.SharedDir(), "data", "nginx", name) - if err := os.MkdirAll(dir, 0750); err != nil { - return nil, errors.Wrap(err, "create store dir") + f := e2e.NewInstrumentedRunnable(e, fmt.Sprintf("nginx-%s", name)). + WithPorts(map[string]int{"http": 80}, "http"). + Future() + + if err := os.MkdirAll(f.Dir(), 0750); err != nil { + return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "create store dir")) } - if err := ioutil.WriteFile(filepath.Join(dir, "nginx.conf"), []byte(conf), 0600); err != nil { - return nil, errors.Wrap(err, "creating nginx config file failed") + if err := ioutil.WriteFile(filepath.Join(f.Dir(), "nginx.conf"), []byte(conf), 0600); err != nil { + return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "creating nginx config file failed")) } - nginx := e2e.NewInstrumentedRunnable(e, fmt.Sprintf("nginx-%s", name)).WithPorts(map[string]int{"http": 80}, "http").Init( + return e2e.NewInstrumentedRunnable(e, fmt.Sprintf("nginx-%s", name)).WithPorts(map[string]int{"http": 80}, "http").Init( e2e.StartOptions{ Image: "docker.io/nginx:1.21.1-alpine", - Volumes: []string{filepath.Join(dir, "/nginx.conf") + ":/etc/nginx/nginx.conf:ro"}, + Volumes: []string{filepath.Join(f.Dir(), "/nginx.conf") + ":/etc/nginx/nginx.conf:ro"}, WaitReadyBackoff: &defaultBackoffConfig, }, ) - - return nginx, nil } // NewMinio returns minio server, used as a local replacement for S3. // TODO(@matej-g): This is a temporary workaround for https://github.com/efficientgo/e2e/issues/11; // after this is addresses fixed all calls should be replaced with e2edb.NewMinio. -func NewMinio(env e2e.Environment, name, bktName string) (e2e.InstrumentedRunnable, error) { +func NewMinio(e e2e.Environment, name, bktName string) e2e.InstrumentedRunnable { image := "minio/minio:RELEASE.2019-12-30T05-45-39Z" minioKESGithubContent := "https://raw.githubusercontent.com/minio/kes/master" commands := []string{ @@ -843,25 +734,24 @@ func NewMinio(env e2e.Environment, name, bktName string) (e2e.InstrumentedRunnab "mkdir -p /data/%s && minio server --certs-dir /shared/data/certs --address :%v --quiet /data", } - if err := os.MkdirAll(filepath.Join(env.SharedDir(), "data", "certs", "CAs"), 0750); err != nil { - return nil, errors.Wrap(err, "create certs dir") + f := e2e.NewInstrumentedRunnable(e, fmt.Sprintf("minio-", name)). + WithPorts(map[string]int{"https": 8090}, "https"). + Future() + + if err := os.MkdirAll(filepath.Join(f.Dir(), "certs", "CAs"), 0750); err != nil { + return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "create certs dir")) } if err := genCerts( - filepath.Join(env.SharedDir(), "data", "certs", "public.crt"), - filepath.Join(env.SharedDir(), "data", "certs", "private.key"), - filepath.Join(env.SharedDir(), "data", "certs", "CAs", "ca.crt"), - env.Name()+"-"+name); err != nil { - return nil, errors.Wrap(err, "fail to generate certs") + filepath.Join(f.Dir(), "certs", "public.crt"), + filepath.Join(f.Dir(), "certs", "private.key"), + filepath.Join(f.Dir(), "certs", "CAs", "ca.crt"), + e.Name()+"-"+name, + ); err != nil { + return e2e.NewErrInstrumentedRunnable(name, errors.Wrap(err, "fail to generate certs")) } - return e2e.NewInstrumentedRunnable( - env, - name, - ).WithPorts( - map[string]int{"https": 8090}, - "https", - ).Init( + return f.Init( e2e.StartOptions{ Image: image, // Create the required bucket before starting minio. @@ -879,11 +769,11 @@ func NewMinio(env e2e.Environment, name, bktName string) (e2e.InstrumentedRunnab "MINIO_KMS_KES_KEY_NAME": "my-minio-key", }, }, - ), nil + ) } func NewMemcached(e e2e.Environment, name string) e2e.InstrumentedRunnable { - memcached := e2e.NewInstrumentedRunnable(e, fmt.Sprintf("memcached-%s", name)).WithPorts(map[string]int{"memcached": 11211}, "memcached").Init( + return e2e.NewInstrumentedRunnable(e, fmt.Sprintf("memcached-%s", name)).WithPorts(map[string]int{"memcached": 11211}, "memcached").Init( e2e.StartOptions{ Image: "docker.io/memcached:1.6.3-alpine", Command: e2e.NewCommand("memcached", []string{"-m 1024", "-I 1m", "-c 1024", "-v"}...), @@ -891,8 +781,6 @@ func NewMemcached(e e2e.Environment, name string) e2e.InstrumentedRunnable { WaitReadyBackoff: &defaultBackoffConfig, }, ) - - return memcached } func NewToolsBucketWeb( @@ -904,10 +792,10 @@ func NewToolsBucketWeb( minTime string, maxTime string, relabelConfig string, -) (e2e.InstrumentedRunnable, error) { +) e2e.InstrumentedRunnable { bktConfigBytes, err := yaml.Marshal(bucketConfig) if err != nil { - return nil, errors.Wrapf(err, "generate tools bucket web config file: %v", bucketConfig) + return e2e.NewErrInstrumentedRunnable(name, errors.Wrapf(err, "generate tools bucket web config file: %v", bucketConfig)) } args := e2e.BuildArgs(map[string]string{ @@ -938,16 +826,13 @@ func NewToolsBucketWeb( args = append([]string{"bucket", "web"}, args...) - toolsBucketWeb := NewService(e, - fmt.Sprintf("toolsBucketWeb-%s", name), - DefaultImage(), - e2e.NewCommand("tools", args...), - e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), - 8080, - 9091, - ) - - return toolsBucketWeb, nil + return e2e.NewInstrumentedRunnable(e, fmt.Sprintf("toolsBucketWeb-%s", name)). + WithPorts(map[string]int{"http": 8080, "grpc": 9091}, "http"). + Init(wrapWithDefaults(e2e.StartOptions{ + Image: DefaultImage(), + Command: e2e.NewCommand("tools", args...), + Readiness: e2e.NewHTTPReadinessProbe("http", "/-/ready", 200, 200), + })) } // genCerts generates certificates and writes those to the provided paths. @@ -1029,9 +914,9 @@ func NewS3Config(bucket, endpoint, basePath string) s3.Config { Insecure: false, HTTPConfig: s3.HTTPConfig{ TLSConfig: objstore.TLSConfig{ - CAFile: filepath.Join(basePath, "data", "certs", "CAs", "ca.crt"), - CertFile: filepath.Join(basePath, "data", "certs", "public.crt"), - KeyFile: filepath.Join(basePath, "data", "certs", "private.key"), + CAFile: filepath.Join(basePath, "certs", "CAs", "ca.crt"), + CertFile: filepath.Join(basePath, "certs", "public.crt"), + KeyFile: filepath.Join(basePath, "certs", "private.key"), }, }, } diff --git a/test/e2e/exemplars_api_test.go b/test/e2e/exemplars_api_test.go index ad2bc049d7..e0c02ca4f1 100644 --- a/test/e2e/exemplars_api_test.go +++ b/test/e2e/exemplars_api_test.go @@ -37,42 +37,40 @@ func TestExemplarsAPI_Fanout(t *testing.T) { t.Cleanup(e2ethanos.CleanScenario(t, e)) qBuilder := e2ethanos.NewQuerierBuilder(e, "query") - qUnitiated := qBuilder.BuildUninitiated() - prom1, sidecar1, err = e2ethanos.NewPrometheusWithSidecar( + prom1, sidecar1 = e2ethanos.NewPrometheusWithSidecar( e, "prom1", - e2ethanos.DefaultPromConfig("ha", 0, "", "", "localhost:9090", qUnitiated.Future().InternalEndpoint("http"), e2ethanos.LocalPrometheusTarget), + e2ethanos.DefaultPromConfig("ha", 0, "", "", "localhost:9090", qBuilder.Future().InternalEndpoint("http"), e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "", e2ethanos.FeatureExemplarStorage, ) - testutil.Ok(t, err) - prom2, sidecar2, err = e2ethanos.NewPrometheusWithSidecar( + prom2, sidecar2 = e2ethanos.NewPrometheusWithSidecar( e, "prom2", - e2ethanos.DefaultPromConfig("ha", 1, "", "", "localhost:9090", qUnitiated.Future().InternalEndpoint("http"), e2ethanos.LocalPrometheusTarget), + e2ethanos.DefaultPromConfig("ha", 1, "", "", "localhost:9090", qBuilder.Future().InternalEndpoint("http"), e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "", e2ethanos.FeatureExemplarStorage, ) - testutil.Ok(t, err) tracingCfg := fmt.Sprintf(`type: JAEGER config: sampler_type: const sampler_param: 1 - service_name: %s`, qUnitiated.Future().Name()) + service_name: %s`, qBuilder.Future().Name()) stores := []string{sidecar1.InternalEndpoint("grpc"), sidecar2.InternalEndpoint("grpc")} - qBuilder = qBuilder.WithExemplarAddresses(stores...). + qBuilder = qBuilder. + WithStoreAddresses(stores...). + WithExemplarAddresses(stores...). WithTracingConfig(tracingCfg) - q, err := qBuilder.Initiate(qUnitiated, stores...) - testutil.Ok(t, err) + q := qBuilder.Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) testutil.Ok(t, err) diff --git a/test/e2e/info_api_test.go b/test/e2e/info_api_test.go index 6122d9ea6b..01e2f4d379 100644 --- a/test/e2e/info_api_test.go +++ b/test/e2e/info_api_test.go @@ -30,24 +30,20 @@ func TestInfo(t *testing.T) { testutil.Ok(t, err) t.Cleanup(e2ethanos.CleanScenario(t, e)) - prom1, sidecar1, err := e2ethanos.NewPrometheusWithSidecar(e, "alone1", e2ethanos.DefaultPromConfig("prom-alone1", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) - prom2, sidecar2, err := e2ethanos.NewPrometheusWithSidecar(e, "alone2", e2ethanos.DefaultPromConfig("prom-alone2", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) - prom3, sidecar3, err := e2ethanos.NewPrometheusWithSidecar(e, "alone3", e2ethanos.DefaultPromConfig("prom-alone3", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) + prom1, sidecar1 := e2ethanos.NewPrometheusWithSidecar(e, "alone1", e2ethanos.DefaultPromConfig("prom-alone1", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") + prom2, sidecar2 := e2ethanos.NewPrometheusWithSidecar(e, "alone2", e2ethanos.DefaultPromConfig("prom-alone2", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") + prom3, sidecar3 := e2ethanos.NewPrometheusWithSidecar(e, "alone3", e2ethanos.DefaultPromConfig("prom-alone3", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") testutil.Ok(t, e2e.StartAndWaitReady(prom1, sidecar1, prom2, sidecar2, prom3, sidecar3)) const bucket = "info-api-test" - m, err := e2ethanos.NewMinio(e, "thanos-minio", bucket) - testutil.Ok(t, err) + m := e2ethanos.NewMinio(e, "thanos-minio", bucket) testutil.Ok(t, e2e.StartAndWaitReady(m)) - store, err := e2ethanos.NewStoreGW( + store := e2ethanos.NewStoreGW( e, "1", client.BucketConfig{ Type: client.S3, - Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), e2ethanos.ContainerSharedDir), + Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), m.InternalDir()), }, "", nil, @@ -59,7 +55,7 @@ func TestInfo(t *testing.T) { // '--endpoint' flag works properly works together with other flags ('--target', '--metadata' etc.). // Register 2 sidecars and 1 storeGW using '--endpoint'. // Register `sidecar3` twice to verify it is deduplicated. - q, err := e2ethanos.NewQuerierBuilder(e, "1", sidecar1.InternalEndpoint("grpc")). + q := e2ethanos.NewQuerierBuilder(e, "1", sidecar1.InternalEndpoint("grpc")). WithTargetAddresses(sidecar1.InternalEndpoint("grpc")). WithMetadataAddresses(sidecar1.InternalEndpoint("grpc")). WithExemplarAddresses(sidecar1.InternalEndpoint("grpc")). @@ -70,8 +66,7 @@ func TestInfo(t *testing.T) { sidecar3.InternalEndpoint("grpc"), store.InternalEndpoint("grpc"), ). - Build() - testutil.Ok(t, err) + Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) expected := map[string][]query.EndpointStatus{ diff --git a/test/e2e/metadata_api_test.go b/test/e2e/metadata_api_test.go index 7369e2d45a..511c01be1f 100644 --- a/test/e2e/metadata_api_test.go +++ b/test/e2e/metadata_api_test.go @@ -27,31 +27,27 @@ func TestMetadataAPI_Fanout(t *testing.T) { // 2x Prometheus. // Each Prometheus scrapes its own metrics and Sidecar's metrics. - prom1, sidecar1, err := e2ethanos.NewPrometheusWithSidecar( + prom1, sidecar1 := e2ethanos.NewPrometheusWithSidecar( e, "prom1", e2ethanos.DefaultPromConfig("ha", 0, "", "", e2ethanos.LocalPrometheusTarget, "sidecar-prom1:8080"), "", e2ethanos.DefaultPrometheusImage(), "", ) - testutil.Ok(t, err) - - prom2, sidecar2, err := e2ethanos.NewPrometheusWithSidecar( + prom2, sidecar2 := e2ethanos.NewPrometheusWithSidecar( e, "prom2", e2ethanos.DefaultPromConfig("ha", 1, "", "", e2ethanos.LocalPrometheusTarget, "sidecar-prom2:8080"), "", e2ethanos.DefaultPrometheusImage(), "", ) - testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(prom1, sidecar1, prom2, sidecar2)) stores := []string{sidecar1.InternalEndpoint("grpc"), sidecar2.InternalEndpoint("grpc")} - q, err := e2ethanos.NewQuerierBuilder( + q := e2ethanos.NewQuerierBuilder( e, "query", stores...). WithMetadataAddresses(stores...). - Build() - testutil.Ok(t, err) + Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) diff --git a/test/e2e/query_frontend_test.go b/test/e2e/query_frontend_test.go index 9f4d1048c2..10ad690712 100644 --- a/test/e2e/query_frontend_test.go +++ b/test/e2e/query_frontend_test.go @@ -32,12 +32,10 @@ func TestQueryFrontend(t *testing.T) { now := time.Now() - prom, sidecar, err := e2ethanos.NewPrometheusWithSidecar(e, "1", e2ethanos.DefaultPromConfig("test", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) + prom, sidecar := e2ethanos.NewPrometheusWithSidecar(e, "1", e2ethanos.DefaultPromConfig("test", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") testutil.Ok(t, e2e.StartAndWaitReady(prom, sidecar)) - q, err := e2ethanos.NewQuerierBuilder(e, "1", sidecar.InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", sidecar.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) inMemoryCacheConfig := queryfrontend.CacheProviderConfig{ @@ -48,8 +46,7 @@ func TestQueryFrontend(t *testing.T) { }, } - queryFrontend, err := e2ethanos.NewQueryFrontend(e, "1", "http://"+q.InternalEndpoint("http"), inMemoryCacheConfig) - testutil.Ok(t, err) + queryFrontend := e2ethanos.NewQueryFrontend(e, "1", "http://"+q.InternalEndpoint("http"), inMemoryCacheConfig) testutil.Ok(t, e2e.StartAndWaitReady(queryFrontend)) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) @@ -402,12 +399,10 @@ func TestQueryFrontendMemcachedCache(t *testing.T) { now := time.Now() - prom, sidecar, err := e2ethanos.NewPrometheusWithSidecar(e, "1", e2ethanos.DefaultPromConfig("test", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) + prom, sidecar := e2ethanos.NewPrometheusWithSidecar(e, "1", e2ethanos.DefaultPromConfig("test", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") testutil.Ok(t, e2e.StartAndWaitReady(prom, sidecar)) - q, err := e2ethanos.NewQuerierBuilder(e, "1", sidecar.InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", sidecar.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) memcached := e2ethanos.NewMemcached(e, "1") @@ -429,8 +424,7 @@ func TestQueryFrontendMemcachedCache(t *testing.T) { }, } - queryFrontend, err := e2ethanos.NewQueryFrontend(e, "1", "http://"+q.InternalEndpoint("http"), memCachedConfig) - testutil.Ok(t, err) + queryFrontend := e2ethanos.NewQueryFrontend(e, "1", "http://"+q.InternalEndpoint("http"), memCachedConfig) testutil.Ok(t, e2e.StartAndWaitReady(queryFrontend)) ctx, cancel := context.WithTimeout(context.Background(), time.Minute) diff --git a/test/e2e/query_test.go b/test/e2e/query_test.go index 50fcb8bbb5..9b241acdbf 100644 --- a/test/e2e/query_test.go +++ b/test/e2e/query_test.go @@ -75,8 +75,7 @@ func TestSidecarNotReady(t *testing.T) { testutil.Ok(t, err) t.Cleanup(e2ethanos.CleanScenario(t, e)) - prom, sidecar, err := e2ethanos.NewPrometheusWithSidecar(e, "alone", e2ethanos.DefaultPromConfig("prom-alone", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) + prom, sidecar := e2ethanos.NewPrometheusWithSidecar(e, "alone", e2ethanos.DefaultPromConfig("prom-alone", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") testutil.Ok(t, e2e.StartAndWaitReady(prom, sidecar)) testutil.Ok(t, prom.Stop()) @@ -109,25 +108,18 @@ func TestQuery(t *testing.T) { testutil.Ok(t, err) t.Cleanup(e2ethanos.CleanScenario(t, e)) - receiver := e2ethanos.NewUninitiatedReceiver(e, "1") - receiverRunnable, err := e2ethanos.NewRoutingAndIngestingReceiverFromService(receiver, e.SharedDir(), 1) - testutil.Ok(t, err) - testutil.Ok(t, e2e.StartAndWaitReady(receiverRunnable)) + receiver := e2ethanos.NewRoutingAndIngestingReceiverFromFuture(e2ethanos.NewFutureReceiver(e, "1"), 1) + testutil.Ok(t, e2e.StartAndWaitReady(receiver)) - prom1, sidecar1, err := e2ethanos.NewPrometheusWithSidecar(e, "alone", e2ethanos.DefaultPromConfig("prom-alone", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) - prom2, sidecar2, err := e2ethanos.NewPrometheusWithSidecar(e, "remote-and-sidecar", e2ethanos.DefaultPromConfig("prom-both-remote-write-and-sidecar", 1234, e2ethanos.RemoteWriteEndpoint(receiver.Future().InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) - prom3, sidecar3, err := e2ethanos.NewPrometheusWithSidecar(e, "ha1", e2ethanos.DefaultPromConfig("prom-ha", 0, "", filepath.Join(e2ethanos.ContainerSharedDir, "", "*.yaml"), e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) - prom4, sidecar4, err := e2ethanos.NewPrometheusWithSidecar(e, "ha2", e2ethanos.DefaultPromConfig("prom-ha", 1, "", filepath.Join(e2ethanos.ContainerSharedDir, "", "*.yaml"), e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) + prom1, sidecar1 := e2ethanos.NewPrometheusWithSidecar(e, "alone", e2ethanos.DefaultPromConfig("prom-alone", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") + prom2, sidecar2 := e2ethanos.NewPrometheusWithSidecar(e, "remote-and-sidecar", e2ethanos.DefaultPromConfig("prom-both-remote-write-and-sidecar", 1234, e2ethanos.RemoteWriteEndpoint(receiver.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") + prom3, sidecar3 := e2ethanos.NewPrometheusWithSidecar(e, "ha1", e2ethanos.DefaultPromConfig("prom-ha", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") + prom4, sidecar4 := e2ethanos.NewPrometheusWithSidecar(e, "ha2", e2ethanos.DefaultPromConfig("prom-ha", 1, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") testutil.Ok(t, e2e.StartAndWaitReady(prom1, sidecar1, prom2, sidecar2, prom3, sidecar3, prom4, sidecar4)) // Querier. Both fileSD and directly by flags. - q, err := e2ethanos.NewQuerierBuilder(e, "1", sidecar1.InternalEndpoint("grpc"), sidecar2.InternalEndpoint("grpc"), receiver.Future().InternalEndpoint("grpc")). - WithFileSDStoreAddresses(sidecar3.InternalEndpoint("grpc"), sidecar4.InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", sidecar1.InternalEndpoint("grpc"), sidecar2.InternalEndpoint("grpc"), receiver.InternalEndpoint("grpc")). + WithFileSDStoreAddresses(sidecar3.InternalEndpoint("grpc"), sidecar4.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) @@ -201,9 +193,8 @@ func TestQueryExternalPrefixWithoutReverseProxy(t *testing.T) { externalPrefix := "test" - q, err := e2ethanos.NewQuerierBuilder(e, "1"). - WithExternalPrefix(externalPrefix).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1"). + WithExternalPrefix(externalPrefix).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) checkNetworkRequests(t, "http://"+q.Endpoint("http")+"/"+externalPrefix+"/graph") @@ -218,9 +209,8 @@ func TestQueryExternalPrefix(t *testing.T) { externalPrefix := "thanos" - q, err := e2ethanos.NewQuerierBuilder(e, "1"). - WithExternalPrefix(externalPrefix).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1"). + WithExternalPrefix(externalPrefix).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) querierURL := urlParse(t, "http://"+q.Endpoint("http")+"/"+externalPrefix) @@ -241,10 +231,10 @@ func TestQueryExternalPrefixAndRoutePrefix(t *testing.T) { externalPrefix := "thanos" routePrefix := "test" - q, err := e2ethanos.NewQuerierBuilder(e, "1"). + q := e2ethanos.NewQuerierBuilder(e, "1"). WithRoutePrefix(routePrefix). WithExternalPrefix(externalPrefix). - Build() + Init() testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(q)) @@ -263,19 +253,14 @@ func TestQueryLabelNames(t *testing.T) { testutil.Ok(t, err) t.Cleanup(e2ethanos.CleanScenario(t, e)) - receiver := e2ethanos.NewUninitiatedReceiver(e, "1") - receiverRunnable, err := e2ethanos.NewRoutingAndIngestingReceiverFromService(receiver, e.SharedDir(), 1) - testutil.Ok(t, err) - testutil.Ok(t, e2e.StartAndWaitReady(receiverRunnable)) + receiver := e2ethanos.NewRoutingAndIngestingReceiverFromFuture(e2ethanos.NewFutureReceiver(e, "1"), 1) + testutil.Ok(t, e2e.StartAndWaitReady(receiver)) - prom1, sidecar1, err := e2ethanos.NewPrometheusWithSidecar(e, "alone", e2ethanos.DefaultPromConfig("prom-alone", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) - prom2, sidecar2, err := e2ethanos.NewPrometheusWithSidecar(e, "remote-and-sidecar", e2ethanos.DefaultPromConfig("prom-both-remote-write-and-sidecar", 1234, e2ethanos.RemoteWriteEndpoint(receiver.Future().InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) + prom1, sidecar1 := e2ethanos.NewPrometheusWithSidecar(e, "alone", e2ethanos.DefaultPromConfig("prom-alone", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") + prom2, sidecar2 := e2ethanos.NewPrometheusWithSidecar(e, "remote-and-sidecar", e2ethanos.DefaultPromConfig("prom-both-remote-write-and-sidecar", 1234, e2ethanos.RemoteWriteEndpoint(receiver.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") testutil.Ok(t, e2e.StartAndWaitReady(prom1, sidecar1, prom2, sidecar2)) - q, err := e2ethanos.NewQuerierBuilder(e, "1", sidecar1.InternalEndpoint("grpc"), sidecar2.InternalEndpoint("grpc"), receiver.Future().InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", sidecar1.InternalEndpoint("grpc"), sidecar2.InternalEndpoint("grpc"), receiver.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) @@ -315,19 +300,14 @@ func TestQueryLabelValues(t *testing.T) { testutil.Ok(t, err) t.Cleanup(e2ethanos.CleanScenario(t, e)) - receiver := e2ethanos.NewUninitiatedReceiver(e, "1") - receiverRunnable, err := e2ethanos.NewRoutingAndIngestingReceiverFromService(receiver, e.SharedDir(), 1) - testutil.Ok(t, err) - testutil.Ok(t, e2e.StartAndWaitReady(receiverRunnable)) + receiver := e2ethanos.NewRoutingAndIngestingReceiverFromFuture(e2ethanos.NewFutureReceiver(e, "1"), 1) + testutil.Ok(t, e2e.StartAndWaitReady(receiver)) - prom1, sidecar1, err := e2ethanos.NewPrometheusWithSidecar(e, "alone", e2ethanos.DefaultPromConfig("prom-alone", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) - prom2, sidecar2, err := e2ethanos.NewPrometheusWithSidecar(e, "remote-and-sidecar", e2ethanos.DefaultPromConfig("prom-both-remote-write-and-sidecar", 1234, e2ethanos.RemoteWriteEndpoint(receiver.Future().InternalEndpoint("remote-write")), ""), "", e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) + prom1, sidecar1 := e2ethanos.NewPrometheusWithSidecar(e, "alone", e2ethanos.DefaultPromConfig("prom-alone", 0, "", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "") + prom2, sidecar2 := e2ethanos.NewPrometheusWithSidecar(e, "remote-and-sidecar", e2ethanos.DefaultPromConfig("prom-both-remote-write-and-sidecar", 1234, e2ethanos.RemoteWriteEndpoint(receiver.InternalEndpoint("remote-write")), ""), "", e2ethanos.DefaultPrometheusImage(), "") testutil.Ok(t, e2e.StartAndWaitReady(prom1, sidecar1, prom2, sidecar2)) - q, err := e2ethanos.NewQuerierBuilder(e, "1", sidecar1.InternalEndpoint("grpc"), sidecar2.InternalEndpoint("grpc"), receiver.Future().InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", sidecar1.InternalEndpoint("grpc"), sidecar2.InternalEndpoint("grpc"), receiver.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) @@ -363,12 +343,10 @@ func TestQueryWithAuthorizedSidecar(t *testing.T) { testutil.Ok(t, err) t.Cleanup(e2ethanos.CleanScenario(t, e)) - prom, sidecar, err := e2ethanos.NewPrometheusWithSidecar(e, "alone", e2ethanos.DefaultPromConfig("prom-alone", 0, "", "", e2ethanos.LocalPrometheusTarget), defaultWebConfig(), e2ethanos.DefaultPrometheusImage(), "") - testutil.Ok(t, err) + prom, sidecar := e2ethanos.NewPrometheusWithSidecar(e, "alone", e2ethanos.DefaultPromConfig("prom-alone", 0, "", "", e2ethanos.LocalPrometheusTarget), defaultWebConfig(), e2ethanos.DefaultPrometheusImage(), "") testutil.Ok(t, e2e.StartAndWaitReady(prom, sidecar)) - q, err := e2ethanos.NewQuerierBuilder(e, "1", []string{sidecar.InternalEndpoint("grpc")}...).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", []string{sidecar.InternalEndpoint("grpc")}...).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) @@ -409,30 +387,30 @@ func TestQueryCompatibilityWithPreInfoAPI(t *testing.T) { testutil.Ok(t, err) t.Cleanup(e2ethanos.CleanScenario(t, e)) - promRulesSubDir := filepath.Join("rules") - testutil.Ok(t, os.MkdirAll(filepath.Join(e.SharedDir(), promRulesSubDir), os.ModePerm)) + qBuilder := e2ethanos.NewQuerierBuilder(e, "1") + + // Use qBuilder work dir to share rules. + promRulesSubDir := "rules" + testutil.Ok(t, os.MkdirAll(filepath.Join(qBuilder.Future().Dir(), promRulesSubDir), os.ModePerm)) // Create the abort_on_partial_response alert for Prometheus. // We don't create the warn_on_partial_response alert as Prometheus has strict yaml unmarshalling. - createRuleFile(t, filepath.Join(e.SharedDir(), promRulesSubDir, "rules.yaml"), testAlertRuleAbortOnPartialResponse) - - qBuilder := e2ethanos.NewQuerierBuilder(e, "1") - qUninit := qBuilder.BuildUninitiated() + createRuleFile(t, filepath.Join(qBuilder.Future().Dir(), promRulesSubDir, "rules.yaml"), testAlertRuleAbortOnPartialResponse) - p1, s1, err := e2ethanos.NewPrometheusWithSidecarCustomImage( + p1, s1 := e2ethanos.NewPrometheusWithSidecarCustomImage( e, "p1", - e2ethanos.DefaultPromConfig("p1", 0, "", filepath.Join(e2ethanos.ContainerSharedDir, promRulesSubDir, "*.yaml"), e2ethanos.LocalPrometheusTarget, qUninit.Future().InternalEndpoint("http")), + e2ethanos.DefaultPromConfig("p1", 0, "", filepath.Join(qBuilder.Future().InternalDir(), promRulesSubDir, "*.yaml"), e2ethanos.LocalPrometheusTarget, qBuilder.Future().InternalEndpoint("http")), "", e2ethanos.DefaultPrometheusImage(), "", tcase.sidecarImage, e2ethanos.FeatureExemplarStorage, ) - testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(p1, s1)) // Newest querier with old --rules --meta etc flags. - q, err := qBuilder. + q := qBuilder. + WithStoreAddresses(s1.InternalEndpoint("grpc")). WithMetadataAddresses(s1.InternalEndpoint("grpc")). WithExemplarAddresses(s1.InternalEndpoint("grpc")). WithTargetAddresses(s1.InternalEndpoint("grpc")). @@ -441,10 +419,9 @@ func TestQueryCompatibilityWithPreInfoAPI(t *testing.T) { config: sampler_type: const sampler_param: 1 - service_name: %s`, qUninit.Future().Name())). // Use fake tracing config to trigger exemplar. + service_name: %s`, qBuilder.Future().Name())). // Use fake tracing config to trigger exemplar. WithImage(tcase.queryImage). - Initiate(qUninit, s1.InternalEndpoint("grpc")) - testutil.Ok(t, err) + Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) @@ -603,13 +580,11 @@ func TestSidecarStorePushdown(t *testing.T) { testutil.Ok(t, err) t.Cleanup(e2ethanos.CleanScenario(t, e)) - prom1, sidecar1, err := e2ethanos.NewPrometheusWithSidecar(e, "p1", e2ethanos.DefaultPromConfig("p1", 0, "", ""), "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") - testutil.Ok(t, err) + prom1, sidecar1 := e2ethanos.NewPrometheusWithSidecar(e, "p1", e2ethanos.DefaultPromConfig("p1", 0, "", ""), "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") testutil.Ok(t, e2e.StartAndWaitReady(prom1, sidecar1)) const bucket = "store_gateway_test" - m, err := e2ethanos.NewMinio(e, "thanos-minio", bucket) - testutil.Ok(t, err) + m := e2ethanos.NewMinio(e, "thanos-minio", bucket) testutil.Ok(t, e2e.StartAndWaitReady(m)) dir := filepath.Join(e.SharedDir(), "tmp") @@ -628,15 +603,14 @@ func TestSidecarStorePushdown(t *testing.T) { l := log.NewLogfmtLogger(os.Stdout) bkt, err := s3.NewBucketWithConfig(l, e2ethanos.NewS3Config(bucket, m.Endpoint("https"), e.SharedDir()), "test") testutil.Ok(t, err) - testutil.Ok(t, objstore.UploadDir(ctx, l, bkt, path.Join(dir, id1.String()), id1.String())) - s1, err := e2ethanos.NewStoreGW( + s1 := e2ethanos.NewStoreGW( e, "1", client.BucketConfig{ Type: client.S3, - Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), e2ethanos.ContainerSharedDir), + Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), m.InternalDir()), }, "", nil, @@ -644,9 +618,7 @@ func TestSidecarStorePushdown(t *testing.T) { testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(s1)) - q, err := e2ethanos.NewQuerierBuilder(e, "1", s1.InternalEndpoint("grpc"), sidecar1.InternalEndpoint("grpc")).WithEnabledFeatures([]string{"query-pushdown"}).Build() - testutil.Ok(t, err) - + q := e2ethanos.NewQuerierBuilder(e, "1", s1.InternalEndpoint("grpc"), sidecar1.InternalEndpoint("grpc")).WithEnabledFeatures([]string{"query-pushdown"}).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) testutil.Ok(t, s1.WaitSumMetrics(e2e.Equals(1), "thanos_blocks_meta_synced")) @@ -821,23 +793,20 @@ func TestSidecarQueryEvaluation(t *testing.T) { testutil.Ok(t, err) t.Cleanup(e2ethanos.CleanScenario(t, e)) - prom1, sidecar1, err := e2ethanos.NewPrometheusWithSidecar(e, "p1", e2ethanos.DefaultPromConfig("p1", 0, "", ""), "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") - testutil.Ok(t, err) + prom1, sidecar1 := e2ethanos.NewPrometheusWithSidecar(e, "p1", e2ethanos.DefaultPromConfig("p1", 0, "", ""), "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") testutil.Ok(t, e2e.StartAndWaitReady(prom1, sidecar1)) - prom2, sidecar2, err := e2ethanos.NewPrometheusWithSidecar(e, "p2", e2ethanos.DefaultPromConfig("p2", 0, "", ""), "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") - testutil.Ok(t, err) + prom2, sidecar2 := e2ethanos.NewPrometheusWithSidecar(e, "p2", e2ethanos.DefaultPromConfig("p2", 0, "", ""), "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") testutil.Ok(t, e2e.StartAndWaitReady(prom2, sidecar2)) endpoints := []string{ sidecar1.InternalEndpoint("grpc"), sidecar2.InternalEndpoint("grpc"), } - q, err := e2ethanos. + q := e2ethanos. NewQuerierBuilder(e, "1", endpoints...). WithEnabledFeatures([]string{"query-pushdown"}). - Build() - testutil.Ok(t, err) + Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) @@ -1191,22 +1160,20 @@ func TestSidecarQueryEvaluationWithDedup(t *testing.T) { testutil.Ok(t, err) t.Cleanup(e2ethanos.CleanScenario(t, e)) - prom1, sidecar1, err := e2ethanos.NewPrometheusWithSidecar(e, "p1", e2ethanos.DefaultPromConfig("p1", 0, "", ""), "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") - testutil.Ok(t, err) + prom1, sidecar1 := e2ethanos.NewPrometheusWithSidecar(e, "p1", e2ethanos.DefaultPromConfig("p1", 0, "", ""), "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") testutil.Ok(t, e2e.StartAndWaitReady(prom1, sidecar1)) - prom2, sidecar2, err := e2ethanos.NewPrometheusWithSidecar(e, "p2", e2ethanos.DefaultPromConfig("p1", 1, "", ""), "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") - testutil.Ok(t, err) + prom2, sidecar2 := e2ethanos.NewPrometheusWithSidecar(e, "p2", e2ethanos.DefaultPromConfig("p1", 1, "", ""), "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") testutil.Ok(t, e2e.StartAndWaitReady(prom2, sidecar2)) endpoints := []string{ sidecar1.InternalEndpoint("grpc"), sidecar2.InternalEndpoint("grpc"), } - q, err := e2ethanos. + q := e2ethanos. NewQuerierBuilder(e, "1", endpoints...). WithEnabledFeatures([]string{"query-pushdown"}). - Build() + Init() testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(q)) @@ -1235,22 +1202,21 @@ func TestSidecarAlignmentPushdown(t *testing.T) { now := time.Now() - prom1, sidecar1, err := e2ethanos.NewPrometheusWithSidecar(e, "p1", e2ethanos.DefaultPromConfig("p1", 0, "", ""), "", e2ethanos.DefaultPrometheusImage(), now.Add(time.Duration(-1)*time.Hour).Format(time.RFC3339), now.Format(time.RFC3339), "remote-write-receiver") - testutil.Ok(t, err) + prom1, sidecar1 := e2ethanos.NewPrometheusWithSidecar(e, "p1", e2ethanos.DefaultPromConfig("p1", 0, "", ""), "", e2ethanos.DefaultPrometheusImage(), now.Add(time.Duration(-1)*time.Hour).Format(time.RFC3339), now.Format(time.RFC3339), "remote-write-receiver") testutil.Ok(t, e2e.StartAndWaitReady(prom1, sidecar1)) endpoints := []string{ sidecar1.InternalEndpoint("grpc"), } - q1, err := e2ethanos. + q1 := e2ethanos. NewQuerierBuilder(e, "1", endpoints...). - Build() + Init() testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(q1)) - q2, err := e2ethanos. + q2 := e2ethanos. NewQuerierBuilder(e, "2", endpoints...). WithEnabledFeatures([]string{"query-pushdown"}). - Build() + Init() testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(q2)) @@ -1316,17 +1282,15 @@ func TestGrpcInstantQuery(t *testing.T) { t.Cleanup(e2ethanos.CleanScenario(t, e)) promConfig := e2ethanos.DefaultPromConfig("p1", 0, "", "") - prom, sidecar, err := e2ethanos.NewPrometheusWithSidecar(e, "p1", promConfig, "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") - testutil.Ok(t, err) + prom, sidecar := e2ethanos.NewPrometheusWithSidecar(e, "p1", promConfig, "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") testutil.Ok(t, e2e.StartAndWaitReady(prom, sidecar)) endpoints := []string{ sidecar.InternalEndpoint("grpc"), } - querier, err := e2ethanos. + querier := e2ethanos. NewQuerierBuilder(e, "1", endpoints...). - Build() - testutil.Ok(t, err) + Init() testutil.Ok(t, e2e.StartAndWaitReady(querier)) now := time.Now() @@ -1424,16 +1388,15 @@ func TestGrpcQueryRange(t *testing.T) { t.Cleanup(e2ethanos.CleanScenario(t, e)) promConfig := e2ethanos.DefaultPromConfig("p1", 0, "", "") - prom, sidecar, err := e2ethanos.NewPrometheusWithSidecar(e, "p1", promConfig, "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") - testutil.Ok(t, err) + prom, sidecar := e2ethanos.NewPrometheusWithSidecar(e, "p1", promConfig, "", e2ethanos.DefaultPrometheusImage(), "", "remote-write-receiver") testutil.Ok(t, e2e.StartAndWaitReady(prom, sidecar)) endpoints := []string{ sidecar.InternalEndpoint("grpc"), } - querier, err := e2ethanos. + querier := e2ethanos. NewQuerierBuilder(e, "1", endpoints...). - Build() + Init() testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(querier)) diff --git a/test/e2e/receive_test.go b/test/e2e/receive_test.go index 8f57e35ff8..26f07faf47 100644 --- a/test/e2e/receive_test.go +++ b/test/e2e/receive_test.go @@ -60,17 +60,14 @@ func TestReceive(t *testing.T) { t.Cleanup(e2ethanos.CleanScenario(t, e)) // Setup Router Ingestor. - i, err := e2ethanos.NewIngestingReceiver(e, "ingestor") - testutil.Ok(t, err) + i := e2ethanos.NewIngestingReceiver(e, "ingestor") testutil.Ok(t, e2e.StartAndWaitReady(i)) // Setup Prometheus - prom, _, err := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, e2ethanos.RemoteWriteEndpoint(i.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) + prom := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, e2ethanos.RemoteWriteEndpoint(i.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) testutil.Ok(t, e2e.StartAndWaitReady(prom)) - q, err := e2ethanos.NewQuerierBuilder(e, "1", i.InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", i.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) @@ -128,12 +125,9 @@ func TestReceive(t *testing.T) { t.Cleanup(e2ethanos.CleanScenario(t, e)) // Setup 3 ingestors. - i1, err := e2ethanos.NewIngestingReceiver(e, "i1") - testutil.Ok(t, err) - i2, err := e2ethanos.NewIngestingReceiver(e, "i2") - testutil.Ok(t, err) - i3, err := e2ethanos.NewIngestingReceiver(e, "i3") - testutil.Ok(t, err) + i1 := e2ethanos.NewIngestingReceiver(e, "i1") + i2 := e2ethanos.NewIngestingReceiver(e, "i2") + i3 := e2ethanos.NewIngestingReceiver(e, "i3") h := receive.HashringConfig{ Endpoints: []string{ @@ -144,20 +138,15 @@ func TestReceive(t *testing.T) { } // Setup 1 distributor - r1, err := e2ethanos.NewRoutingReceiver(e, "r1", 2, h) - testutil.Ok(t, err) + r1 := e2ethanos.NewRoutingReceiver(e, "r1", 2, h) testutil.Ok(t, e2e.StartAndWaitReady(i1, i2, i3, r1)) - prom1, _, err := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, e2ethanos.RemoteWriteEndpoint(r1.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) - prom2, _, err := e2ethanos.NewPrometheus(e, "2", e2ethanos.DefaultPromConfig("prom2", 0, e2ethanos.RemoteWriteEndpoint(r1.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) - prom3, _, err := e2ethanos.NewPrometheus(e, "3", e2ethanos.DefaultPromConfig("prom3", 0, e2ethanos.RemoteWriteEndpoint(r1.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) + prom1 := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, e2ethanos.RemoteWriteEndpoint(r1.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) + prom2 := e2ethanos.NewPrometheus(e, "2", e2ethanos.DefaultPromConfig("prom2", 0, e2ethanos.RemoteWriteEndpoint(r1.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) + prom3 := e2ethanos.NewPrometheus(e, "3", e2ethanos.DefaultPromConfig("prom3", 0, e2ethanos.RemoteWriteEndpoint(r1.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) testutil.Ok(t, e2e.StartAndWaitReady(prom1, prom2, prom3)) - q, err := e2ethanos.NewQuerierBuilder(e, "1", i1.InternalEndpoint("grpc"), i2.InternalEndpoint("grpc"), i3.InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", i1.InternalEndpoint("grpc"), i2.InternalEndpoint("grpc"), i3.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) @@ -235,42 +224,32 @@ func TestReceive(t *testing.T) { t.Cleanup(e2ethanos.CleanScenario(t, e)) // Setup ingestors. - i1, err := e2ethanos.NewIngestingReceiver(e, "i1") - testutil.Ok(t, err) - i2, err := e2ethanos.NewIngestingReceiver(e, "i2") - testutil.Ok(t, err) - i3, err := e2ethanos.NewIngestingReceiver(e, "i3") - testutil.Ok(t, err) + i1 := e2ethanos.NewIngestingReceiver(e, "i1") + i2 := e2ethanos.NewIngestingReceiver(e, "i2") + i3 := e2ethanos.NewIngestingReceiver(e, "i3") // Setup distributors - r2, err := e2ethanos.NewRoutingReceiver(e, "r2", 2, receive.HashringConfig{ + r2 := e2ethanos.NewRoutingReceiver(e, "r2", 2, receive.HashringConfig{ Endpoints: []string{ i2.InternalEndpoint("grpc"), i3.InternalEndpoint("grpc"), }, }) - testutil.Ok(t, err) - - r1, err := e2ethanos.NewRoutingReceiver(e, "r1", 2, receive.HashringConfig{ + r1 := e2ethanos.NewRoutingReceiver(e, "r1", 2, receive.HashringConfig{ Endpoints: []string{ i1.InternalEndpoint("grpc"), r2.InternalEndpoint("grpc"), }, }) - testutil.Ok(t, err) - testutil.Ok(t, e2e.StartAndWaitReady(i1, i2, i3, r1, r2)) - //Setup Prometheuses - prom1, _, err := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, e2ethanos.RemoteWriteEndpoint(r1.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) - prom2, _, err := e2ethanos.NewPrometheus(e, "2", e2ethanos.DefaultPromConfig("prom2", 0, e2ethanos.RemoteWriteEndpoint(r1.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) + // Setup Prometheus. + prom1 := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, e2ethanos.RemoteWriteEndpoint(r1.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) + prom2 := e2ethanos.NewPrometheus(e, "2", e2ethanos.DefaultPromConfig("prom2", 0, e2ethanos.RemoteWriteEndpoint(r1.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) testutil.Ok(t, e2e.StartAndWaitReady(prom1, prom2)) //Setup Querier - q, err := e2ethanos.NewQuerierBuilder(e, "1", i1.InternalEndpoint("grpc"), i2.InternalEndpoint("grpc"), i3.InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", i1.InternalEndpoint("grpc"), i2.InternalEndpoint("grpc"), i3.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) @@ -340,109 +319,31 @@ func TestReceive(t *testing.T) { testutil.Ok(t, err) t.Cleanup(e2ethanos.CleanScenario(t, e)) - r1 := e2ethanos.NewUninitiatedReceiver(e, "1") - r2 := e2ethanos.NewUninitiatedReceiver(e, "2") - r3 := e2ethanos.NewUninitiatedReceiver(e, "3") - - h := receive.HashringConfig{ - Endpoints: []string{ - r1.Future().InternalEndpoint("grpc"), - r2.Future().InternalEndpoint("grpc"), - r3.Future().InternalEndpoint("grpc"), - }, - } - - // Create with hashring config. - r1Runnable, err := e2ethanos.NewRoutingAndIngestingReceiverFromService(r1, e.SharedDir(), 1, h) - testutil.Ok(t, err) - r2Runnable, err := e2ethanos.NewRoutingAndIngestingReceiverFromService(r2, e.SharedDir(), 1, h) - testutil.Ok(t, err) - r3Runnable, err := e2ethanos.NewRoutingAndIngestingReceiverFromService(r3, e.SharedDir(), 1, h) - testutil.Ok(t, err) - testutil.Ok(t, e2e.StartAndWaitReady(r1Runnable, r2Runnable, r3Runnable)) - - prom1, _, err := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, e2ethanos.RemoteWriteEndpoint(r1.Future().InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) - prom2, _, err := e2ethanos.NewPrometheus(e, "2", e2ethanos.DefaultPromConfig("prom2", 0, e2ethanos.RemoteWriteEndpoint(r2.Future().InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) - prom3, _, err := e2ethanos.NewPrometheus(e, "3", e2ethanos.DefaultPromConfig("prom3", 0, e2ethanos.RemoteWriteEndpoint(r3.Future().InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) - testutil.Ok(t, e2e.StartAndWaitReady(prom1, prom2, prom3)) - - q, err := e2ethanos.NewQuerierBuilder(e, "1", r1.Future().InternalEndpoint("grpc"), r2.Future().InternalEndpoint("grpc"), r3.Future().InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) - testutil.Ok(t, e2e.StartAndWaitReady(q)) - - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) - t.Cleanup(cancel) - - testutil.Ok(t, q.WaitSumMetricsWithOptions(e2e.Equals(3), []string{"thanos_store_nodes_grpc_connections"}, e2e.WaitMissingMetrics())) - - queryAndAssertSeries(t, ctx, q.Endpoint("http"), e2ethanos.QueryUpWithoutInstance, time.Now, promclient.QueryOptions{ - Deduplicate: false, - }, []model.Metric{ - { - "job": "myself", - "prometheus": "prom1", - "receive": "receive-2", - "replica": "0", - "tenant_id": "default-tenant", - }, - { - "job": "myself", - "prometheus": "prom2", - "receive": "receive-1", - "replica": "0", - "tenant_id": "default-tenant", - }, - { - "job": "myself", - "prometheus": "prom3", - "receive": "receive-2", - "replica": "0", - "tenant_id": "default-tenant", - }, - }) - }) - - t.Run("hashring with config watcher", func(t *testing.T) { - t.Parallel() - - e, err := e2e.NewDockerEnvironment("e2e_test_receive_hashring_config_watcher") - testutil.Ok(t, err) - t.Cleanup(e2ethanos.CleanScenario(t, e)) - - r1 := e2ethanos.NewUninitiatedReceiver(e, "1") - r2 := e2ethanos.NewUninitiatedReceiver(e, "2") - r3 := e2ethanos.NewUninitiatedReceiver(e, "3") + r1 := e2ethanos.NewFutureReceiver(e, "1") + r2 := e2ethanos.NewFutureReceiver(e, "2") + r3 := e2ethanos.NewFutureReceiver(e, "3") h := receive.HashringConfig{ Endpoints: []string{ - r1.Future().InternalEndpoint("grpc"), - r2.Future().InternalEndpoint("grpc"), - r3.Future().InternalEndpoint("grpc"), + r1.InternalEndpoint("grpc"), + r2.InternalEndpoint("grpc"), + r3.InternalEndpoint("grpc"), }, } - // Create with hashring config. - // TODO(kakkoyun): Update config file and wait config watcher to reconcile hashring. - r1Runnable, err := e2ethanos.NewRoutingAndIngestingReceiverWithConfigWatcher(r1, e.SharedDir(), 1, h) - testutil.Ok(t, err) - r2Runnable, err := e2ethanos.NewRoutingAndIngestingReceiverWithConfigWatcher(r2, e.SharedDir(), 1, h) - testutil.Ok(t, err) - r3Runnable, err := e2ethanos.NewRoutingAndIngestingReceiverWithConfigWatcher(r3, e.SharedDir(), 1, h) - testutil.Ok(t, err) + // Create with hashring config watcher. + r1Runnable := e2ethanos.NewRoutingAndIngestingReceiverFromFuture(r1, 1, h) + r2Runnable := e2ethanos.NewRoutingAndIngestingReceiverFromFuture(r2, 1, h) + r3Runnable := e2ethanos.NewRoutingAndIngestingReceiverFromFuture(r3, 1, h) testutil.Ok(t, e2e.StartAndWaitReady(r1Runnable, r2Runnable, r3Runnable)) - prom1, _, err := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, e2ethanos.RemoteWriteEndpoint(r1.Future().InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) - prom2, _, err := e2ethanos.NewPrometheus(e, "2", e2ethanos.DefaultPromConfig("prom2", 0, e2ethanos.RemoteWriteEndpoint(r2.Future().InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) - prom3, _, err := e2ethanos.NewPrometheus(e, "3", e2ethanos.DefaultPromConfig("prom3", 0, e2ethanos.RemoteWriteEndpoint(r3.Future().InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) + prom1 := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, e2ethanos.RemoteWriteEndpoint(r1.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) + prom2 := e2ethanos.NewPrometheus(e, "2", e2ethanos.DefaultPromConfig("prom2", 0, e2ethanos.RemoteWriteEndpoint(r2.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) + prom3 := e2ethanos.NewPrometheus(e, "3", e2ethanos.DefaultPromConfig("prom3", 0, e2ethanos.RemoteWriteEndpoint(r3.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(prom1, prom2, prom3)) - q, err := e2ethanos.NewQuerierBuilder(e, "1", r1.Future().InternalEndpoint("grpc"), r2.Future().InternalEndpoint("grpc"), r3.Future().InternalEndpoint("grpc")).Build() + q := e2ethanos.NewQuerierBuilder(e, "1", r1.InternalEndpoint("grpc"), r2.InternalEndpoint("grpc"), r3.InternalEndpoint("grpc")).Init() testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(q)) @@ -490,33 +391,28 @@ func TestReceive(t *testing.T) { // receivers and the test verifies that the time series are // replicated to all of the nodes. - r1 := e2ethanos.NewUninitiatedReceiver(e, "1") - r2 := e2ethanos.NewUninitiatedReceiver(e, "2") - r3 := e2ethanos.NewUninitiatedReceiver(e, "3") + r1 := e2ethanos.NewFutureReceiver(e, "1") + r2 := e2ethanos.NewFutureReceiver(e, "2") + r3 := e2ethanos.NewFutureReceiver(e, "3") h := receive.HashringConfig{ Endpoints: []string{ - r1.Future().InternalEndpoint("grpc"), - r2.Future().InternalEndpoint("grpc"), - r3.Future().InternalEndpoint("grpc"), + r1.InternalEndpoint("grpc"), + r2.InternalEndpoint("grpc"), + r3.InternalEndpoint("grpc"), }, } // Create with hashring config. - r1Runnable, err := e2ethanos.NewRoutingAndIngestingReceiverFromService(r1, e.SharedDir(), 3, h) - testutil.Ok(t, err) - r2Runnable, err := e2ethanos.NewRoutingAndIngestingReceiverFromService(r2, e.SharedDir(), 3, h) - testutil.Ok(t, err) - r3Runnable, err := e2ethanos.NewRoutingAndIngestingReceiverFromService(r3, e.SharedDir(), 3, h) - testutil.Ok(t, err) + r1Runnable := e2ethanos.NewRoutingAndIngestingReceiverFromFuture(r1, 3, h) + r2Runnable := e2ethanos.NewRoutingAndIngestingReceiverFromFuture(r2, 3, h) + r3Runnable := e2ethanos.NewRoutingAndIngestingReceiverFromFuture(r3, 3, h) testutil.Ok(t, e2e.StartAndWaitReady(r1Runnable, r2Runnable, r3Runnable)) - prom1, _, err := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, e2ethanos.RemoteWriteEndpoint(r1.Future().InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) + prom1 := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, e2ethanos.RemoteWriteEndpoint(r1.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) testutil.Ok(t, e2e.StartAndWaitReady(prom1)) - q, err := e2ethanos.NewQuerierBuilder(e, "1", r1.Future().InternalEndpoint("grpc"), r2.Future().InternalEndpoint("grpc"), r3.Future().InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", r1.InternalEndpoint("grpc"), r2.InternalEndpoint("grpc"), r3.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) @@ -562,31 +458,27 @@ func TestReceive(t *testing.T) { // receivers is dead. In this case, replication should still // succeed and the time series should be replicated to the other nodes. - r1 := e2ethanos.NewUninitiatedReceiver(e, "1") - r2 := e2ethanos.NewUninitiatedReceiver(e, "2") - r3 := e2ethanos.NewUninitiatedReceiver(e, "3") + r1 := e2ethanos.NewFutureReceiver(e, "1") + r2 := e2ethanos.NewFutureReceiver(e, "2") + r3 := e2ethanos.NewFutureReceiver(e, "3") h := receive.HashringConfig{ Endpoints: []string{ - r1.Future().InternalEndpoint("grpc"), - r2.Future().InternalEndpoint("grpc"), - r3.Future().InternalEndpoint("grpc"), + r1.InternalEndpoint("grpc"), + r2.InternalEndpoint("grpc"), + r3.InternalEndpoint("grpc"), }, } // Create with hashring config. - r1Runnable, err := e2ethanos.NewRoutingAndIngestingReceiverFromService(r1, e.SharedDir(), 3, h) - testutil.Ok(t, err) - r2Runnable, err := e2ethanos.NewRoutingAndIngestingReceiverFromService(r2, e.SharedDir(), 3, h) - testutil.Ok(t, err) + r1Runnable := e2ethanos.NewRoutingAndIngestingReceiverFromFuture(r1, 3, h) + r2Runnable := e2ethanos.NewRoutingAndIngestingReceiverFromFuture(r2, 3, h) testutil.Ok(t, e2e.StartAndWaitReady(r1Runnable, r2Runnable)) - prom1, _, err := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, e2ethanos.RemoteWriteEndpoint(r1.Future().InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) + prom1 := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, e2ethanos.RemoteWriteEndpoint(r1.InternalEndpoint("remote-write")), "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) testutil.Ok(t, e2e.StartAndWaitReady(prom1)) - q, err := e2ethanos.NewQuerierBuilder(e, "1", r1.Future().InternalEndpoint("grpc"), r2.Future().InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", r1.InternalEndpoint("grpc"), r2.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) @@ -621,33 +513,27 @@ func TestReceive(t *testing.T) { testutil.Ok(t, err) t.Cleanup(e2ethanos.CleanScenario(t, e)) - r1 := e2ethanos.NewUninitiatedReceiver(e, "1") + r1 := e2ethanos.NewFutureReceiver(e, "1") h := receive.HashringConfig{ Endpoints: []string{ - r1.Future().InternalEndpoint("grpc"), + r1.InternalEndpoint("grpc"), }, } // Create with hashring config. - r1Runnable, err := e2ethanos.NewRoutingAndIngestingReceiverFromService(r1, e.SharedDir(), 1, h) - testutil.Ok(t, err) + r1Runnable := e2ethanos.NewRoutingAndIngestingReceiverFromFuture(r1, 1, h) testutil.Ok(t, e2e.StartAndWaitReady(r1Runnable)) - rp1, err := e2ethanos.NewReverseProxy(e, "1", "tenant-1", "http://"+r1.Future().InternalEndpoint("remote-write")) - testutil.Ok(t, err) - rp2, err := e2ethanos.NewReverseProxy(e, "2", "tenant-2", "http://"+r1.Future().InternalEndpoint("remote-write")) - testutil.Ok(t, err) + rp1 := e2ethanos.NewReverseProxy(e, "1", "tenant-1", "http://"+r1.InternalEndpoint("remote-write")) + rp2 := e2ethanos.NewReverseProxy(e, "2", "tenant-2", "http://"+r1.InternalEndpoint("remote-write")) testutil.Ok(t, e2e.StartAndWaitReady(rp1, rp2)) - prom1, _, err := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, "http://"+rp1.InternalEndpoint("http")+"/api/v1/receive", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) - prom2, _, err := e2ethanos.NewPrometheus(e, "2", e2ethanos.DefaultPromConfig("prom2", 0, "http://"+rp2.InternalEndpoint("http")+"/api/v1/receive", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) - testutil.Ok(t, err) + prom1 := e2ethanos.NewPrometheus(e, "1", e2ethanos.DefaultPromConfig("prom1", 0, "http://"+rp1.InternalEndpoint("http")+"/api/v1/receive", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) + prom2 := e2ethanos.NewPrometheus(e, "2", e2ethanos.DefaultPromConfig("prom2", 0, "http://"+rp2.InternalEndpoint("http")+"/api/v1/receive", "", e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage()) testutil.Ok(t, e2e.StartAndWaitReady(prom1, prom2)) - q, err := e2ethanos.NewQuerierBuilder(e, "1", r1.Future().InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", r1.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) t.Cleanup(cancel) diff --git a/test/e2e/rule_test.go b/test/e2e/rule_test.go index 7c41fd5c8b..e1aaef4c97 100644 --- a/test/e2e/rule_test.go +++ b/test/e2e/rule_test.go @@ -228,29 +228,24 @@ func TestRule(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) t.Cleanup(cancel) - // Prepare work dirs. - rulesSubDir := filepath.Join("rules") - rulesPath := filepath.Join(e.SharedDir(), rulesSubDir) - testutil.Ok(t, os.MkdirAll(rulesPath, os.ModePerm)) - createRuleFiles(t, rulesPath) + am1 := e2ethanos.NewAlertmanager(e, "1") + am2 := e2ethanos.NewAlertmanager(e, "2") + testutil.Ok(t, e2e.StartAndWaitReady(am1, am2)) + + // Use am1 work dir for shared resources. amTargetsSubDir := filepath.Join("rules_am_targets") - testutil.Ok(t, os.MkdirAll(filepath.Join(e.SharedDir(), amTargetsSubDir), os.ModePerm)) + testutil.Ok(t, os.MkdirAll(filepath.Join(am1.Dir(), amTargetsSubDir), os.ModePerm)) queryTargetsSubDir := filepath.Join("rules_query_targets") - testutil.Ok(t, os.MkdirAll(filepath.Join(e.SharedDir(), queryTargetsSubDir), os.ModePerm)) - - am1, err := e2ethanos.NewAlertmanager(e, "1") - testutil.Ok(t, err) - am2, err := e2ethanos.NewAlertmanager(e, "2") - testutil.Ok(t, err) - testutil.Ok(t, e2e.StartAndWaitReady(am1, am2)) + testutil.Ok(t, os.MkdirAll(filepath.Join(am1.Dir(), queryTargetsSubDir), os.ModePerm)) + rulesSubDir := filepath.Join("rules") r := e2ethanos.NewTSDBRuler(e, "1", rulesSubDir, []alert.AlertmanagerConfig{ { EndpointsConfig: httpconfig.EndpointsConfig{ FileSDConfigs: []httpconfig.FileSDConfig{ { // FileSD which will be used to register discover dynamically am1. - Files: []string{filepath.Join(e2ethanos.ContainerSharedDir, amTargetsSubDir, "*.yaml")}, + Files: []string{filepath.Join(am1.InternalDir(), amTargetsSubDir, "*.yaml")}, RefreshInterval: model.Duration(time.Second), }, }, @@ -269,7 +264,7 @@ func TestRule(t *testing.T) { FileSDConfigs: []httpconfig.FileSDConfig{ { // FileSD which will be used to register discover dynamically q. - Files: []string{filepath.Join(e2ethanos.ContainerSharedDir, queryTargetsSubDir, "*.yaml")}, + Files: []string{filepath.Join(am1.InternalDir(), queryTargetsSubDir, "*.yaml")}, RefreshInterval: model.Duration(time.Second), }, }, @@ -279,8 +274,11 @@ func TestRule(t *testing.T) { }) testutil.Ok(t, e2e.StartAndWaitReady(r)) - q, err := e2ethanos.NewQuerierBuilder(e, "1", r.InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + rulesPath := filepath.Join(r.Dir(), rulesSubDir) + testutil.Ok(t, os.MkdirAll(rulesPath, os.ModePerm)) + createRuleFiles(t, rulesPath) + + q := e2ethanos.NewQuerierBuilder(e, "1", r.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) t.Run("no query configured", func(t *testing.T) { @@ -481,22 +479,18 @@ func TestRule_CanRemoteWriteData(t *testing.T) { createRuleFile(t, filepath.Join(rulesPath, fmt.Sprintf("rules-%d.yaml", i)), rule) } - am, err := e2ethanos.NewAlertmanager(e, "1") - testutil.Ok(t, err) + am := e2ethanos.NewAlertmanager(e, "1") testutil.Ok(t, e2e.StartAndWaitReady(am)) - receiver, err := e2ethanos.NewIngestingReceiver(e, "1") - testutil.Ok(t, err) + receiver := e2ethanos.NewIngestingReceiver(e, "1") testutil.Ok(t, e2e.StartAndWaitReady(receiver)) rwURL := urlParse(t, e2ethanos.RemoteWriteEndpoint(receiver.InternalEndpoint("remote-write"))) - receiver2, err := e2ethanos.NewIngestingReceiver(e, "2") - testutil.Ok(t, err) + receiver2 := e2ethanos.NewIngestingReceiver(e, "2") testutil.Ok(t, e2e.StartAndWaitReady(receiver2)) rwURL2 := urlParse(t, e2ethanos.RemoteWriteEndpoint(receiver2.InternalEndpoint("remote-write"))) - q, err := e2ethanos.NewQuerierBuilder(e, "1", receiver.InternalEndpoint("grpc"), receiver2.InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", receiver.InternalEndpoint("grpc"), receiver2.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) r := e2ethanos.NewStatelessRuler(e, "1", rulesSubDir, []alert.AlertmanagerConfig{ { diff --git a/test/e2e/rules_api_test.go b/test/e2e/rules_api_test.go index 47db429b6a..cbb49270e4 100644 --- a/test/e2e/rules_api_test.go +++ b/test/e2e/rules_api_test.go @@ -35,43 +35,41 @@ func TestRulesAPI_Fanout(t *testing.T) { testutil.Ok(t, err) t.Cleanup(e2ethanos.CleanScenario(t, e)) + qBuilder := e2ethanos.NewQuerierBuilder(e, "query") + + // Use querier work dir for shared resources (easiest to obtain). promRulesSubDir := filepath.Join("rules") - testutil.Ok(t, os.MkdirAll(filepath.Join(e.SharedDir(), promRulesSubDir), os.ModePerm)) + testutil.Ok(t, os.MkdirAll(filepath.Join(qBuilder.Future().Dir(), promRulesSubDir), os.ModePerm)) // Create the abort_on_partial_response alert for Prometheus. // We don't create the warn_on_partial_response alert as Prometheus has strict yaml unmarshalling. - createRuleFile(t, filepath.Join(e.SharedDir(), promRulesSubDir, "rules.yaml"), testAlertRuleAbortOnPartialResponse) + createRuleFile(t, filepath.Join(qBuilder.Future().Dir(), promRulesSubDir, "rules.yaml"), testAlertRuleAbortOnPartialResponse) thanosRulesSubDir := filepath.Join("thanos-rules") - testutil.Ok(t, os.MkdirAll(filepath.Join(e.SharedDir(), thanosRulesSubDir), os.ModePerm)) - createRuleFiles(t, filepath.Join(e.SharedDir(), thanosRulesSubDir)) + testutil.Ok(t, os.MkdirAll(filepath.Join(qBuilder.Future().Dir(), thanosRulesSubDir), os.ModePerm)) + createRuleFiles(t, filepath.Join(qBuilder.Future().Dir(), thanosRulesSubDir)) // We create a rule group with limit. - createRuleFile(t, filepath.Join(e.SharedDir(), thanosRulesSubDir, "rules-with-limit.yaml"), testAlertRuleWithLimit) + createRuleFile(t, filepath.Join(qBuilder.Future().Dir(), thanosRulesSubDir, "rules-with-limit.yaml"), testAlertRuleWithLimit) // 2x Prometheus. - prom1, sidecar1, err := e2ethanos.NewPrometheusWithSidecar( + prom1, sidecar1 := e2ethanos.NewPrometheusWithSidecar( e, "prom1", - e2ethanos.DefaultPromConfig("ha", 0, "", filepath.Join(e2ethanos.ContainerSharedDir, promRulesSubDir, "*.yaml"), e2ethanos.LocalPrometheusTarget), + e2ethanos.DefaultPromConfig("ha", 0, "", filepath.Join(qBuilder.Future().InternalDir(), promRulesSubDir, "*.yaml"), e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "", ) - testutil.Ok(t, err) - prom2, sidecar2, err := e2ethanos.NewPrometheusWithSidecar( + prom2, sidecar2 := e2ethanos.NewPrometheusWithSidecar( e, "prom2", - e2ethanos.DefaultPromConfig("ha", 1, "", filepath.Join(e2ethanos.ContainerSharedDir, promRulesSubDir, "*.yaml"), e2ethanos.LocalPrometheusTarget), + e2ethanos.DefaultPromConfig("ha", 1, "", filepath.Join(qBuilder.Future().InternalDir(), promRulesSubDir, "*.yaml"), e2ethanos.LocalPrometheusTarget), "", e2ethanos.DefaultPrometheusImage(), "", ) - testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(prom1, sidecar1, prom2, sidecar2)) - qBuilder := e2ethanos.NewQuerierBuilder(e, "query") - qUninit := qBuilder.BuildUninitiated() - queryCfg := []httpconfig.Config{ { EndpointsConfig: httpconfig.EndpointsConfig{ - StaticAddresses: []string{qUninit.Future().InternalEndpoint("http")}, + StaticAddresses: []string{qBuilder.Future().InternalEndpoint("http")}, Scheme: "http", }, }, @@ -83,8 +81,10 @@ func TestRulesAPI_Fanout(t *testing.T) { testutil.Ok(t, e2e.StartAndWaitReady(r1, r2)) stores := []string{sidecar1.InternalEndpoint("grpc"), sidecar2.InternalEndpoint("grpc"), r1.InternalEndpoint("grpc"), r2.InternalEndpoint("grpc")} - q, err := qBuilder.WithRuleAddresses(stores...).Initiate(qUninit, stores...) - testutil.Ok(t, err) + q := qBuilder. + WithStoreAddresses(stores...). + WithRuleAddresses(stores...). + Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) diff --git a/test/e2e/store_gateway_test.go b/test/e2e/store_gateway_test.go index 8c034b7a2f..eed71c65ba 100644 --- a/test/e2e/store_gateway_test.go +++ b/test/e2e/store_gateway_test.go @@ -43,8 +43,7 @@ func TestStoreGateway(t *testing.T) { t.Cleanup(e2ethanos.CleanScenario(t, e)) const bucket = "store_gateway_test" - m, err := e2ethanos.NewMinio(e, "thanos-minio", bucket) - testutil.Ok(t, err) + m := e2ethanos.NewMinio(e, "thanos-minio", bucket) testutil.Ok(t, e2e.StartAndWaitReady(m)) memcached := e2ethanos.NewMemcached(e, "1") @@ -58,12 +57,12 @@ metafile_exists_ttl: 0s metafile_doesnt_exist_ttl: 0s metafile_content_ttl: 0s`, memcached.InternalEndpoint("memcached")) - s1, err := e2ethanos.NewStoreGW( + s1 := e2ethanos.NewStoreGW( e, "1", client.BucketConfig{ Type: client.S3, - Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), e2ethanos.ContainerSharedDir), + Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), m.InternalDir()), }, memcachedConfig, nil, @@ -78,8 +77,7 @@ metafile_content_ttl: 0s`, memcached.InternalEndpoint("memcached")) // Ensure bucket UI. ensureGETStatusCode(t, http.StatusOK, "http://"+path.Join(s1.Endpoint("http"), "loaded")) - q, err := e2ethanos.NewQuerierBuilder(e, "1", s1.InternalEndpoint("grpc")).WithEnabledFeatures([]string{"promql-negative-offset", "promql-at-modifier"}).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", s1.InternalEndpoint("grpc")).WithEnabledFeatures([]string{"promql-negative-offset", "promql-at-modifier"}).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) dir := filepath.Join(e.SharedDir(), "tmp") @@ -284,8 +282,7 @@ func TestStoreGatewayMemcachedCache(t *testing.T) { t.Cleanup(e2ethanos.CleanScenario(t, e)) const bucket = "store_gateway_memcached_cache_test" - m, err := e2ethanos.NewMinio(e, "thanos-minio", bucket) - testutil.Ok(t, err) + m := e2ethanos.NewMinio(e, "thanos-minio", bucket) testutil.Ok(t, e2e.StartAndWaitReady(m)) memcached := e2ethanos.NewMemcached(e, "1") @@ -296,12 +293,12 @@ config: addresses: [%s] blocks_iter_ttl: 0s`, memcached.InternalEndpoint("memcached")) - s1, err := e2ethanos.NewStoreGW( + s1 := e2ethanos.NewStoreGW( e, "1", client.BucketConfig{ Type: client.S3, - Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), e2ethanos.ContainerSharedDir), + Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), m.InternalDir()), }, memcachedConfig, nil, @@ -309,8 +306,7 @@ blocks_iter_ttl: 0s`, memcached.InternalEndpoint("memcached")) testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(s1)) - q, err := e2ethanos.NewQuerierBuilder(e, "1", s1.InternalEndpoint("grpc")).Build() - testutil.Ok(t, err) + q := e2ethanos.NewQuerierBuilder(e, "1", s1.InternalEndpoint("grpc")).Init() testutil.Ok(t, e2e.StartAndWaitReady(q)) dir := filepath.Join(e.SharedDir(), "tmp") @@ -389,8 +385,7 @@ func TestStoreGatewayGroupCache(t *testing.T) { t.Cleanup(e2ethanos.CleanScenario(t, e)) const bucket = "store_gateway_groupcache_test" - m, err := e2ethanos.NewMinio(e, "thanos-minio", bucket) - testutil.Ok(t, err) + m := e2ethanos.NewMinio(e, "thanos-minio", bucket) testutil.Ok(t, e2e.StartAndWaitReady(m)) groupcacheConfig := `type: GROUPCACHE @@ -407,51 +402,43 @@ metafile_exists_ttl: 0s metafile_doesnt_exist_ttl: 0s metafile_content_ttl: 0s` - store1, err := e2ethanos.NewStoreGW( + store1 := e2ethanos.NewStoreGW( e, "1", client.BucketConfig{ Type: client.S3, - Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), e2ethanos.ContainerSharedDir), + Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), m.InternalDir()), }, fmt.Sprintf(groupcacheConfig, 1), nil, ) - testutil.Ok(t, err) - testutil.Ok(t, e2e.StartAndWaitReady(store1)) - - store2, err := e2ethanos.NewStoreGW( + store2 := e2ethanos.NewStoreGW( e, "2", client.BucketConfig{ Type: client.S3, - Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), e2ethanos.ContainerSharedDir), + Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), m.InternalDir()), }, fmt.Sprintf(groupcacheConfig, 2), nil, ) - testutil.Ok(t, err) - testutil.Ok(t, e2e.StartAndWaitReady(store2)) - - store3, err := e2ethanos.NewStoreGW( + store3 := e2ethanos.NewStoreGW( e, "3", client.BucketConfig{ Type: client.S3, - Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), e2ethanos.ContainerSharedDir), + Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), m.InternalDir()), }, fmt.Sprintf(groupcacheConfig, 3), nil, ) + testutil.Ok(t, e2e.StartAndWaitReady(store1, store2, store3)) - testutil.Ok(t, err) - testutil.Ok(t, e2e.StartAndWaitReady(store3)) - - q, err := e2ethanos.NewQuerierBuilder(e, "1", + q := e2ethanos.NewQuerierBuilder(e, "1", store1.InternalEndpoint("grpc"), store2.InternalEndpoint("grpc"), store3.InternalEndpoint("grpc"), - ).Build() + ).Init() testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(q)) diff --git a/test/e2e/targets_api_test.go b/test/e2e/targets_api_test.go index 10dd7f38cf..df6ad83eda 100644 --- a/test/e2e/targets_api_test.go +++ b/test/e2e/targets_api_test.go @@ -32,28 +32,26 @@ func TestTargetsAPI_Fanout(t *testing.T) { t.Cleanup(e2ethanos.CleanScenario(t, e)) // 2x Prometheus. - prom1, sidecar1, err := e2ethanos.NewPrometheusWithSidecar( + prom1, sidecar1 := e2ethanos.NewPrometheusWithSidecar( e, "prom1", e2ethanos.DefaultPromConfig("ha", 0, "", "", e2ethanos.LocalPrometheusTarget, "localhost:80"), "", e2ethanos.DefaultPrometheusImage(), "", ) - testutil.Ok(t, err) - prom2, sidecar2, err := e2ethanos.NewPrometheusWithSidecar( + prom2, sidecar2 := e2ethanos.NewPrometheusWithSidecar( e, "prom2", e2ethanos.DefaultPromConfig("ha", 1, "", "", e2ethanos.LocalPrometheusTarget, "localhost:80"), "", e2ethanos.DefaultPrometheusImage(), "", ) - testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(prom1, sidecar1, prom2, sidecar2)) stores := []string{sidecar1.InternalEndpoint("grpc"), sidecar2.InternalEndpoint("grpc")} - q, err := e2ethanos.NewQuerierBuilder(e, "query", stores...). + q := e2ethanos.NewQuerierBuilder(e, "query", stores...). WithTargetAddresses(stores...). - Build() + Init() testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(q)) diff --git a/test/e2e/tools_bucket_web_test.go b/test/e2e/tools_bucket_web_test.go index e2861ae6b4..6867b81a2d 100644 --- a/test/e2e/tools_bucket_web_test.go +++ b/test/e2e/tools_bucket_web_test.go @@ -39,16 +39,15 @@ func TestToolsBucketWebExternalPrefixWithoutReverseProxy(t *testing.T) { externalPrefix := "testThanos" const bucket = "compact_test" - m, err := e2ethanos.NewMinio(e, "thanos", bucket) - testutil.Ok(t, err) + m := e2ethanos.NewMinio(e, "thanos", bucket) testutil.Ok(t, e2e.StartAndWaitReady(m)) svcConfig := client.BucketConfig{ Type: client.S3, - Config: e2ethanos.NewS3Config(bucket, m.Endpoint("https"), e2ethanos.ContainerSharedDir), + Config: e2ethanos.NewS3Config(bucket, m.Endpoint("https"), m.InternalDir()), } - b, err := e2ethanos.NewToolsBucketWeb( + b := e2ethanos.NewToolsBucketWeb( e, "1", svcConfig, @@ -58,7 +57,6 @@ func TestToolsBucketWebExternalPrefixWithoutReverseProxy(t *testing.T) { "", "", ) - testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(b)) checkNetworkRequests(t, "http://"+b.Endpoint("http")+"/"+externalPrefix+"/blocks") @@ -73,16 +71,15 @@ func TestToolsBucketWebExternalPrefix(t *testing.T) { externalPrefix := "testThanos" const bucket = "toolsBucketWeb_test" - m, err := e2ethanos.NewMinio(e, "thanos", bucket) - testutil.Ok(t, err) + m := e2ethanos.NewMinio(e, "thanos", bucket) testutil.Ok(t, e2e.StartAndWaitReady(m)) svcConfig := client.BucketConfig{ Type: client.S3, - Config: e2ethanos.NewS3Config(bucket, m.Endpoint("https"), e2ethanos.ContainerSharedDir), + Config: e2ethanos.NewS3Config(bucket, m.Endpoint("https"), m.InternalDir()), } - b, err := e2ethanos.NewToolsBucketWeb( + b := e2ethanos.NewToolsBucketWeb( e, "1", svcConfig, @@ -92,7 +89,6 @@ func TestToolsBucketWebExternalPrefix(t *testing.T) { "", "", ) - testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(b)) toolsBucketWebURL := urlParse(t, "http://"+b.Endpoint("http")+"/"+externalPrefix) @@ -113,16 +109,16 @@ func TestToolsBucketWebExternalPrefixAndRoutePrefix(t *testing.T) { externalPrefix := "testThanos" routePrefix := "test" const bucket = "toolsBucketWeb_test" - m, err := e2ethanos.NewMinio(e, "thanos", bucket) + m := e2ethanos.NewMinio(e, "thanos", bucket) testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(m)) svcConfig := client.BucketConfig{ Type: client.S3, - Config: e2ethanos.NewS3Config(bucket, m.Endpoint("https"), e2ethanos.ContainerSharedDir), + Config: e2ethanos.NewS3Config(bucket, m.Endpoint("https"), m.InternalDir()), } - b, err := e2ethanos.NewToolsBucketWeb( + b := e2ethanos.NewToolsBucketWeb( e, "1", svcConfig, @@ -132,7 +128,6 @@ func TestToolsBucketWebExternalPrefixAndRoutePrefix(t *testing.T) { "", "", ) - testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(b)) toolsBucketWebURL := urlParse(t, "http://"+b.Endpoint("http")+"/"+routePrefix) @@ -145,23 +140,26 @@ func TestToolsBucketWebExternalPrefixAndRoutePrefix(t *testing.T) { func TestToolsBucketWebWithTimeAndRelabelFilter(t *testing.T) { t.Parallel() - // Create network. + e, err := e2e.NewDockerEnvironment("e2e_test_tools_bucket_web_time_and_relabel_filter") testutil.Ok(t, err) t.Cleanup(e2ethanos.CleanScenario(t, e)) + // Create Minio. const bucket = "toolsBucketWeb_test" - m, err := e2ethanos.NewMinio(e, "thanos", bucket) - testutil.Ok(t, err) + m := e2ethanos.NewMinio(e, "thanos", bucket) testutil.Ok(t, e2e.StartAndWaitReady(m)) + // Create bucket. logger := log.NewLogfmtLogger(os.Stdout) bkt, err := s3.NewBucketWithConfig(logger, e2ethanos.NewS3Config(bucket, m.Endpoint("https"), e.SharedDir()), "tools") testutil.Ok(t, err) + // Create share dir for upload. dir := filepath.Join(e.SharedDir(), "tmp") testutil.Ok(t, os.MkdirAll(dir, os.ModePerm)) + // Upload blocks. now, err := time.Parse(time.RFC3339, "2021-07-24T08:00:00Z") testutil.Ok(t, err) @@ -198,9 +196,9 @@ func TestToolsBucketWebWithTimeAndRelabelFilter(t *testing.T) { // Start thanos tool bucket web. svcConfig := client.BucketConfig{ Type: client.S3, - Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), e2ethanos.ContainerSharedDir), + Config: e2ethanos.NewS3Config(bucket, m.InternalEndpoint("https"), m.InternalDir()), } - b, err := e2ethanos.NewToolsBucketWeb( + b := e2ethanos.NewToolsBucketWeb( e, "1", svcConfig, @@ -213,11 +211,12 @@ func TestToolsBucketWebWithTimeAndRelabelFilter(t *testing.T) { regex: "b" source_labels: ["tenant_id"]`, ) - testutil.Ok(t, err) testutil.Ok(t, e2e.StartAndWaitReady(b)) + // Request blocks api. resp, err := http.DefaultClient.Get("http://" + b.Endpoint("http") + "/api/v1/blocks") testutil.Ok(t, err) + testutil.Equals(t, http.StatusOK, resp.StatusCode) defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) @@ -228,6 +227,7 @@ func TestToolsBucketWebWithTimeAndRelabelFilter(t *testing.T) { } testutil.Ok(t, json.Unmarshal(body, &data)) testutil.Equals(t, "success", data.Status) + // Filtered by time and relabel, result only one blocks. testutil.Equals(t, 1, len(data.Data.Blocks)) testutil.Equals(t, data.Data.Blocks[0].MaxTime, blocks[0].maxt) From bf3a31c9522799b847669efd123028e173a62786 Mon Sep 17 00:00:00 2001 From: Bartlomiej Plotka Date: Mon, 9 May 2022 19:11:08 +0200 Subject: [PATCH 07/14] Removed alert combatibiltiy test for now. Signed-off-by: Bartlomiej Plotka --- test/e2e/compatibility_test.go | 77 ---------------------------------- 1 file changed, 77 deletions(-) diff --git a/test/e2e/compatibility_test.go b/test/e2e/compatibility_test.go index 0fc114ef16..408d4c32a6 100644 --- a/test/e2e/compatibility_test.go +++ b/test/e2e/compatibility_test.go @@ -4,8 +4,6 @@ package e2e_test import ( - "bytes" - "fmt" "io/ioutil" "os" "path/filepath" @@ -14,10 +12,6 @@ import ( "github.com/efficientgo/e2e" e2edb "github.com/efficientgo/e2e/db" - common_cfg "github.com/prometheus/common/config" - "github.com/prometheus/prometheus/config" - "github.com/thanos-io/thanos/pkg/alert" - "github.com/thanos-io/thanos/pkg/httpconfig" "github.com/thanos-io/thanos/pkg/testutil" "github.com/thanos-io/thanos/test/e2e/e2ethanos" ) @@ -116,74 +110,3 @@ query_tweaks: return ret }() } - -// TestAlertCompliance tests Alert compatibility against https://github.com/prometheus/compliance/blob/main/alert_generator. -// NOTE: This requires a dockerization of compliance framework: https://github.com/prometheus/compliance/pull/46 -func TestAlertCompliance(t *testing.T) { - //t.Skip("This is an interactive test, using https://github.com/prometheus/compliance/tree/main/alert_generator. This tool is not optimized for CI runs (e.g. it infinitely retries") - - t.Run("staleness ruler", func(t *testing.T) { - e, err := e2e.NewDockerEnvironment("alert_compatibility") - testutil.Ok(t, err) - t.Cleanup(e.Close) - - // Start receive + Querier. - receive := e2ethanos.NewIngestingReceiver(e, "receive") - querierBuilder := e2ethanos.NewQuerierBuilder(e, "query", receive.InternalEndpoint("grpc")) - - compliance := e.Runnable("alert_generator_compliance_tester").WithPorts(map[string]int{"http": 8080}).Init(e2e.StartOptions{ - Image: "alert_generator_compliance_tester:latest", - Command: e2e.NewCommandRunUntilStop(), - }) - ruler := e2ethanos.NewStatelessRuler(e, "1", "rules", []alert.AlertmanagerConfig{ - { - EndpointsConfig: httpconfig.EndpointsConfig{ - StaticAddresses: []string{compliance.InternalEndpoint("http")}, - Scheme: "http", - }, - Timeout: amTimeout, - APIVersion: alert.APIv1, - }, - }, []httpconfig.Config{ - { - EndpointsConfig: httpconfig.EndpointsConfig{ - StaticAddresses: []string{ - querierBuilder.Future().InternalEndpoint("http"), - }, - Scheme: "http", - }, - }, - }, []*config.RemoteWriteConfig{ - {URL: &common_cfg.URL{URL: urlParse(t, e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("remote-write")))}, Name: "thanos-receiver"}, - }) - query := querierBuilder.WithRuleAddresses(ruler.InternalEndpoint("grpc")).Init() - testutil.Ok(t, e2e.StartAndWaitReady(receive, query, ruler, compliance)) - - // Pull rules.yaml: - { - var stdout bytes.Buffer - testutil.Ok(t, compliance.Exec(e2e.NewCommand("cat", "/rules.yaml"), e2e.WithExecOptionStdout(&stdout))) - testutil.Ok(t, os.MkdirAll(filepath.Join(ruler.Dir(), "rules"), os.ModePerm)) - testutil.Ok(t, os.WriteFile(filepath.Join(ruler.Dir(), "rules", "rules.yaml"), stdout.Bytes(), os.ModePerm)) - } - - testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "test-thanos.yaml"), []byte(alertCompatConfig(receive, query)), os.ModePerm)) - - fmt.Println(alertCompatConfig(receive, query)) - - testutil.Ok(t, compliance.Exec(e2e.NewCommand( - "/alert_generator_compliance_tester", "-config-file", filepath.Join(compliance.InternalDir(), "test-thanos.yaml")), - )) - }) -} - -// nolint (it's still used in skipped test). -func alertCompatConfig(receive e2e.Runnable, query e2e.Runnable) string { - return fmt.Sprintf(`settings: - remote_write_url: '%s' - query_base_url: 'http://%s' - rules_and_alerts_api_base_url: 'http://%s' - alert_reception_server_port: 8080 - alert_message_parser: default -`, e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("http")), query.InternalEndpoint("http"), query.InternalEndpoint("http")) -} From 7418254fa6eef821f7ff0e4cd50316f57aefcd00 Mon Sep 17 00:00:00 2001 From: Bartlomiej Plotka Date: Mon, 9 May 2022 19:14:03 +0200 Subject: [PATCH 08/14] e2e: Added test for compatibility. Signed-off-by: Bartlomiej Plotka --- cmd/thanos/rule.go | 2 +- test/e2e/compatibility_test.go | 87 ++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/cmd/thanos/rule.go b/cmd/thanos/rule.go index cec7c66022..6e9b0a6e78 100644 --- a/cmd/thanos/rule.go +++ b/cmd/thanos/rule.go @@ -120,7 +120,7 @@ func registerRule(app *extkingpin.App) { walCompression := cmd.Flag("tsdb.wal-compression", "Compress the tsdb WAL.").Default("true").Bool() cmd.Flag("data-dir", "data directory").Default("data/").StringVar(&conf.dataDir) - cmd.Flag("rule-file", "Rule files that should be used by rule manager. Can be in glob format (repeated)."). + cmd.Flag("rule-file", "Rule files that should be used by rule manager. Can be in glob format (repeated). Note that rules are not automatically detected, use SIGHUP or do HTTP POST /-/reload to re-read them."). Default("rules/").StringsVar(&conf.ruleFiles) cmd.Flag("resend-delay", "Minimum amount of time to wait before resending an alert to Alertmanager."). Default("1m").DurationVar(&conf.resendDelay) diff --git a/test/e2e/compatibility_test.go b/test/e2e/compatibility_test.go index 408d4c32a6..8de7f9dc93 100644 --- a/test/e2e/compatibility_test.go +++ b/test/e2e/compatibility_test.go @@ -4,7 +4,11 @@ package e2e_test import ( + "bytes" + "fmt" + "io" "io/ioutil" + "net/http" "os" "path/filepath" "testing" @@ -12,6 +16,10 @@ import ( "github.com/efficientgo/e2e" e2edb "github.com/efficientgo/e2e/db" + common_cfg "github.com/prometheus/common/config" + "github.com/prometheus/prometheus/config" + "github.com/thanos-io/thanos/pkg/alert" + "github.com/thanos-io/thanos/pkg/httpconfig" "github.com/thanos-io/thanos/pkg/testutil" "github.com/thanos-io/thanos/test/e2e/e2ethanos" ) @@ -110,3 +118,82 @@ query_tweaks: return ret }() } + +// TestAlertCompliance tests Alert compatibility against https://github.com/prometheus/compliance/blob/main/alert_generator. +// NOTE: This requires a dockerization of compliance framework: https://github.com/prometheus/compliance/pull/46 +func TestAlertCompliance(t *testing.T) { + //t.Skip("This is an interactive test, using https://github.com/prometheus/compliance/tree/main/alert_generator. This tool is not optimized for CI runs (e.g. it infinitely retries") + + t.Run("staleness ruler", func(t *testing.T) { + e, err := e2e.NewDockerEnvironment("alert_compatibility") + testutil.Ok(t, err) + t.Cleanup(e.Close) + + // Start receive + Querier. + receive := e2ethanos.NewIngestingReceiver(e, "receive") + querierBuilder := e2ethanos.NewQuerierBuilder(e, "query", receive.InternalEndpoint("grpc")) + + compliance := e.Runnable("alert_generator_compliance_tester").WithPorts(map[string]int{"http": 8080}).Init(e2e.StartOptions{ + Image: "alert_generator_compliance_tester:latest", + Command: e2e.NewCommandRunUntilStop(), + }) + ruler := e2ethanos.NewStatelessRuler(e, "1", "rules", []alert.AlertmanagerConfig{ + { + EndpointsConfig: httpconfig.EndpointsConfig{ + StaticAddresses: []string{compliance.InternalEndpoint("http")}, + Scheme: "http", + }, + Timeout: amTimeout, + APIVersion: alert.APIv1, + }, + }, []httpconfig.Config{ + { + EndpointsConfig: httpconfig.EndpointsConfig{ + StaticAddresses: []string{ + querierBuilder.Future().InternalEndpoint("http"), + }, + Scheme: "http", + }, + }, + }, []*config.RemoteWriteConfig{ + {URL: &common_cfg.URL{URL: urlParse(t, e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("remote-write")))}, Name: "thanos-receiver"}, + }) + query := querierBuilder.WithRuleAddresses(ruler.InternalEndpoint("grpc")).Init() + testutil.Ok(t, e2e.StartAndWaitReady(receive, query, ruler, compliance)) + + // Pull rules.yaml: + { + var stdout bytes.Buffer + testutil.Ok(t, compliance.Exec(e2e.NewCommand("cat", "/rules.yaml"), e2e.WithExecOptionStdout(&stdout))) + testutil.Ok(t, os.MkdirAll(filepath.Join(ruler.Dir(), "rules"), os.ModePerm)) + testutil.Ok(t, os.WriteFile(filepath.Join(ruler.Dir(), "rules", "rules.yaml"), stdout.Bytes(), os.ModePerm)) + + // Reload ruler. + resp, err := http.Post("http://"+ruler.Endpoint("http")+"/-/reload", "", nil) + testutil.Ok(t, err) + defer func() { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + }() + testutil.Equals(t, http.StatusOK, resp.StatusCode) + } + testutil.Ok(t, ioutil.WriteFile(filepath.Join(compliance.Dir(), "test-thanos.yaml"), []byte(alertCompatConfig(receive, query)), os.ModePerm)) + + fmt.Println(alertCompatConfig(receive, query)) + + testutil.Ok(t, compliance.Exec(e2e.NewCommand( + "/alert_generator_compliance_tester", "-config-file", filepath.Join(compliance.InternalDir(), "test-thanos.yaml")), + )) + }) +} + +// nolint (it's still used in skipped test). +func alertCompatConfig(receive e2e.Runnable, query e2e.Runnable) string { + return fmt.Sprintf(`settings: + remote_write_url: '%s' + query_base_url: 'http://%s' + rules_and_alerts_api_base_url: 'http://%s' + alert_reception_server_port: 8080 + alert_message_parser: default +`, e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("http")), query.InternalEndpoint("http"), query.InternalEndpoint("http")) +} From 1b9e19b0090605d66f4defdef68348b9dc2de923 Mon Sep 17 00:00:00 2001 From: Bartlomiej Plotka Date: Tue, 10 May 2022 10:21:17 +0200 Subject: [PATCH 09/14] Added Querier /alerts API. Signed-off-by: Bartlomiej Plotka --- pkg/api/query/v1.go | 45 ++++++++++++++++++++++++++++++++++ pkg/api/query/v1_test.go | 6 ++--- test/e2e/compatibility_test.go | 2 +- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/pkg/api/query/v1.go b/pkg/api/query/v1.go index 5da44c7a2d..a4f33a986a 100644 --- a/pkg/api/query/v1.go +++ b/pkg/api/query/v1.go @@ -185,6 +185,7 @@ func (qapi *QueryAPI) Register(r *route.Router, tracer opentracing.Tracer, logge r.Get("/stores", instr("stores", qapi.stores)) + r.Get("/alerts", instr("alerts", NewAlertsHandler(qapi.ruleGroups, qapi.enableRulePartialResponse))) r.Get("/rules", instr("rules", NewRulesHandler(qapi.ruleGroups, qapi.enableRulePartialResponse))) r.Get("/targets", instr("targets", NewTargetsHandler(qapi.targets, qapi.enableTargetPartialResponse))) @@ -760,6 +761,50 @@ func NewTargetsHandler(client targets.UnaryClient, enablePartialResponse bool) f } } +// NewAlertsHandler created handler compatible with HTTP /api/v1/alerts https://prometheus.io/docs/prometheus/latest/querying/api/#alerts +// which uses gRPC Unary Rules API (Rules API works for both /alerts and /rules). +func NewAlertsHandler(client rules.UnaryClient, enablePartialResponse bool) func(*http.Request) (interface{}, []error, *api.ApiError) { + ps := storepb.PartialResponseStrategy_ABORT + if enablePartialResponse { + ps = storepb.PartialResponseStrategy_WARN + } + + return func(r *http.Request) (interface{}, []error, *api.ApiError) { + span, ctx := tracing.StartSpan(r.Context(), "receive_http_request") + defer span.Finish() + + var ( + groups *rulespb.RuleGroups + warnings storage.Warnings + err error + ) + + // TODO(bwplotka): Allow exactly the same functionality as query API: passing replica, dedup and partial response as HTTP params as well. + req := &rulespb.RulesRequest{ + Type: rulespb.RulesRequest_ALERT, + PartialResponseStrategy: ps, + } + tracing.DoInSpan(ctx, "retrieve_rules", func(ctx context.Context) { + groups, warnings, err = client.Rules(ctx, req) + }) + if err != nil { + return nil, nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Errorf("error retrieving rules: %v", err)} + } + + var resp struct{ Alerts []*rulespb.AlertInstance } + for _, g := range groups.Groups { + for _, r := range g.Rules { + a := r.GetAlert() + if a == nil { + continue + } + resp.Alerts = append(resp.Alerts, a.Alerts...) + } + } + return resp, warnings, nil + } +} + // NewRulesHandler created handler compatible with HTTP /api/v1/rules https://prometheus.io/docs/prometheus/latest/querying/api/#rules // which uses gRPC Unary Rules API. func NewRulesHandler(client rules.UnaryClient, enablePartialResponse bool) func(*http.Request) (interface{}, []error, *api.ApiError) { diff --git a/pkg/api/query/v1_test.go b/pkg/api/query/v1_test.go index c9f97c0eb4..e7358036ca 100644 --- a/pkg/api/query/v1_test.go +++ b/pkg/api/query/v1_test.go @@ -1713,7 +1713,7 @@ func TestRulesHandler(t *testing.T) { Type: "alerting", }, } - var tests = []test{ + for _, test := range []test{ { response: &testpromcompatibility.RuleDiscovery{ RuleGroups: []*testpromcompatibility.RuleGroup{ @@ -1770,9 +1770,7 @@ func TestRulesHandler(t *testing.T) { }, }, }, - } - - for _, test := range tests { + } { t.Run(fmt.Sprintf("endpoint=%s/method=%s/query=%q", "rules", http.MethodGet, test.query.Encode()), func(t *testing.T) { // Build a context with the correct request params. ctx := context.Background() diff --git a/test/e2e/compatibility_test.go b/test/e2e/compatibility_test.go index 8de7f9dc93..faa48c1eae 100644 --- a/test/e2e/compatibility_test.go +++ b/test/e2e/compatibility_test.go @@ -195,5 +195,5 @@ func alertCompatConfig(receive e2e.Runnable, query e2e.Runnable) string { rules_and_alerts_api_base_url: 'http://%s' alert_reception_server_port: 8080 alert_message_parser: default -`, e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("http")), query.InternalEndpoint("http"), query.InternalEndpoint("http")) +`, e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("remote-write")), query.InternalEndpoint("http"), query.InternalEndpoint("http")) } From e40d25edbc748ba1c0e465afb38661284e1808d4 Mon Sep 17 00:00:00 2001 From: Bartlomiej Plotka Date: Tue, 10 May 2022 10:39:27 +0200 Subject: [PATCH 10/14] e2e:Added replica labels. Signed-off-by: Bartlomiej Plotka --- test/e2e/compatibility_test.go | 10 ++++++++-- test/e2e/e2ethanos/services.go | 28 ++++++++++++++-------------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/test/e2e/compatibility_test.go b/test/e2e/compatibility_test.go index faa48c1eae..72b65036dc 100644 --- a/test/e2e/compatibility_test.go +++ b/test/e2e/compatibility_test.go @@ -131,7 +131,7 @@ func TestAlertCompliance(t *testing.T) { // Start receive + Querier. receive := e2ethanos.NewIngestingReceiver(e, "receive") - querierBuilder := e2ethanos.NewQuerierBuilder(e, "query", receive.InternalEndpoint("grpc")) + querierBuilder := e2ethanos.NewQuerierBuilder(e, "query") compliance := e.Runnable("alert_generator_compliance_tester").WithPorts(map[string]int{"http": 8080}).Init(e2e.StartOptions{ Image: "alert_generator_compliance_tester:latest", @@ -158,7 +158,13 @@ func TestAlertCompliance(t *testing.T) { }, []*config.RemoteWriteConfig{ {URL: &common_cfg.URL{URL: urlParse(t, e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("remote-write")))}, Name: "thanos-receiver"}, }) - query := querierBuilder.WithRuleAddresses(ruler.InternalEndpoint("grpc")).Init() + query := querierBuilder. + WithStoreAddresses(receive.InternalEndpoint("grpc")). + WithRuleAddresses(ruler.InternalEndpoint("grpc")). + // We deduplicate by this, since alert compatibility tool requires clean metric without labels + // attached by receivers. + WithReplicaLabels("receive", "tenant_id"). + Init() testutil.Ok(t, e2e.StartAndWaitReady(receive, query, ruler, compliance)) // Pull rules.yaml: diff --git a/test/e2e/e2ethanos/services.go b/test/e2e/e2ethanos/services.go index 4461aca0a1..ad61b50714 100644 --- a/test/e2e/e2ethanos/services.go +++ b/test/e2e/e2ethanos/services.go @@ -183,18 +183,22 @@ type QuerierBuilder struct { enableFeatures []string endpoints []string + replicaLabels []string tracingConfig string f e2e.FutureInstrumentedRunnable } func NewQuerierBuilder(e e2e.Environment, name string, storeAddresses ...string) *QuerierBuilder { + const replicaLabel = "replica" + return &QuerierBuilder{ environment: e, sharedDir: e.SharedDir(), name: name, storeAddresses: storeAddresses, image: DefaultImage(), + replicaLabels: []string{replicaLabel}, } } @@ -258,6 +262,12 @@ func (q *QuerierBuilder) WithTracingConfig(tracingConfig string) *QuerierBuilder return q } +// WithReplicaLabels replaces default [replica] replica label configuration for the querier. +func (q *QuerierBuilder) WithReplicaLabels(labels ...string) *QuerierBuilder { + q.replicaLabels = labels + return q +} + func (q *QuerierBuilder) Future() e2e.FutureInstrumentedRunnable { if q.f != nil { return q.f @@ -285,47 +295,41 @@ func (q *QuerierBuilder) Init() e2e.InstrumentedRunnable { } func (q *QuerierBuilder) collectArgs(f e2e.FutureInstrumentedRunnable) ([]string, error) { - const replicaLabel = "replica" - args := e2e.BuildArgs(map[string]string{ "--debug.name": fmt.Sprintf("querier-%v", q.name), "--grpc-address": ":9091", "--grpc-grace-period": "0s", "--http-address": ":8080", - "--query.replica-label": replicaLabel, "--store.sd-dns-interval": "5s", "--log.level": infoLogLevel, "--query.max-concurrent": "1", "--store.sd-interval": "5s", }) + + for _, repl := range q.replicaLabels { + args = append(args, "--query.replica-label="+repl) + } for _, addr := range q.storeAddresses { args = append(args, "--store="+addr) } - for _, addr := range q.ruleAddresses { args = append(args, "--rule="+addr) } - for _, addr := range q.targetAddresses { args = append(args, "--target="+addr) } - for _, addr := range q.metadataAddresses { args = append(args, "--metadata="+addr) } - for _, addr := range q.exemplarAddresses { args = append(args, "--exemplar="+addr) } - for _, feature := range q.enableFeatures { args = append(args, "--enable-feature="+feature) } - for _, addr := range q.endpoints { args = append(args, "--endpoint="+addr) } - if len(q.fileSDStoreAddresses) > 0 { if err := os.MkdirAll(f.Dir(), 0750); err != nil { return nil, errors.Wrap(err, "create query dir failed") @@ -347,19 +351,15 @@ func (q *QuerierBuilder) collectArgs(f e2e.FutureInstrumentedRunnable) ([]string args = append(args, "--store.sd-files="+filepath.Join(f.InternalDir(), "filesd.yaml")) } - if q.routePrefix != "" { args = append(args, "--web.route-prefix="+q.routePrefix) } - if q.externalPrefix != "" { args = append(args, "--web.external-prefix="+q.externalPrefix) } - if q.tracingConfig != "" { args = append(args, "--tracing.config="+q.tracingConfig) } - return args, nil } From c13a9759d9d43ae04cc4dd6c8dd5841370ba82c8 Mon Sep 17 00:00:00 2001 From: Bartlomiej Plotka Date: Tue, 10 May 2022 10:52:49 +0200 Subject: [PATCH 11/14] Option to remove replica-label. Signed-off-by: Bartlomiej Plotka --- test/e2e/compatibility_test.go | 2 +- test/e2e/e2ethanos/services.go | 14 +++++++++----- test/e2e/rule_test.go | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/test/e2e/compatibility_test.go b/test/e2e/compatibility_test.go index 72b65036dc..42fd49df49 100644 --- a/test/e2e/compatibility_test.go +++ b/test/e2e/compatibility_test.go @@ -157,7 +157,7 @@ func TestAlertCompliance(t *testing.T) { }, }, []*config.RemoteWriteConfig{ {URL: &common_cfg.URL{URL: urlParse(t, e2ethanos.RemoteWriteEndpoint(receive.InternalEndpoint("remote-write")))}, Name: "thanos-receiver"}, - }) + }, false) query := querierBuilder. WithStoreAddresses(receive.InternalEndpoint("grpc")). WithRuleAddresses(ruler.InternalEndpoint("grpc")). diff --git a/test/e2e/e2ethanos/services.go b/test/e2e/e2ethanos/services.go index ad61b50714..88a892ceb1 100644 --- a/test/e2e/e2ethanos/services.go +++ b/test/e2e/e2ethanos/services.go @@ -476,14 +476,14 @@ func NewIngestingReceiver(e e2e.Environment, name string) e2e.InstrumentedRunnab } func NewTSDBRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config) e2e.InstrumentedRunnable { - return newRuler(e, name, ruleSubDir, amCfg, queryCfg, nil) + return newRuler(e, name, ruleSubDir, amCfg, queryCfg, nil, true) } -func NewStatelessRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig) e2e.InstrumentedRunnable { - return newRuler(e, name, ruleSubDir, amCfg, queryCfg, remoteWriteCfg) +func NewStatelessRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig, withReplicaLabel bool) e2e.InstrumentedRunnable { + return newRuler(e, name, ruleSubDir, amCfg, queryCfg, remoteWriteCfg, withReplicaLabel) } -func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig) e2e.InstrumentedRunnable { +func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.AlertmanagerConfig, queryCfg []httpconfig.Config, remoteWriteCfg []*config.RemoteWriteConfig, withReplicaLabel bool) e2e.InstrumentedRunnable { f := e2e.NewInstrumentedRunnable(e, fmt.Sprintf("rule-%v", name)). WithPorts(map[string]int{"http": 8080, "grpc": 9091}, "http"). Future() @@ -509,7 +509,6 @@ func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.Alertman "--grpc-address": ":9091", "--grpc-grace-period": "0s", "--http-address": ":8080", - "--label": fmt.Sprintf(`replica="%s"`, name), "--data-dir": f.InternalDir(), "--rule-file": filepath.Join(f.InternalDir(), ruleSubDir, "*.yaml"), "--eval-interval": "1s", @@ -520,6 +519,11 @@ func newRuler(e e2e.Environment, name, ruleSubDir string, amCfg []alert.Alertman "--query.sd-dns-interval": "1s", "--resend-delay": "5s", } + + if withReplicaLabel { + ruleArgs["--label"] = fmt.Sprintf("replica=%s", name) + } + if remoteWriteCfg != nil { rwCfgBytes, err := yaml.Marshal(struct { RemoteWriteConfigs []*config.RemoteWriteConfig `yaml:"remote_write,omitempty"` diff --git a/test/e2e/rule_test.go b/test/e2e/rule_test.go index e1aaef4c97..80f8124305 100644 --- a/test/e2e/rule_test.go +++ b/test/e2e/rule_test.go @@ -515,7 +515,7 @@ func TestRule_CanRemoteWriteData(t *testing.T) { }, []*config.RemoteWriteConfig{ {URL: &common_cfg.URL{URL: rwURL}, Name: "thanos-receiver"}, {URL: &common_cfg.URL{URL: rwURL2}, Name: "thanos-receiver2"}, - }) + }, true) testutil.Ok(t, e2e.StartAndWaitReady(r)) // Wait until remote write samples are written to receivers successfully. From d786eaca158608ada96a982ac33f140d6ed8d4c1 Mon Sep 17 00:00:00 2001 From: Bartlomiej Plotka Date: Tue, 10 May 2022 10:56:31 +0200 Subject: [PATCH 12/14] skip. Signed-off-by: Bartlomiej Plotka --- test/e2e/compatibility_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/compatibility_test.go b/test/e2e/compatibility_test.go index 42fd49df49..3002f781bc 100644 --- a/test/e2e/compatibility_test.go +++ b/test/e2e/compatibility_test.go @@ -122,7 +122,7 @@ query_tweaks: // TestAlertCompliance tests Alert compatibility against https://github.com/prometheus/compliance/blob/main/alert_generator. // NOTE: This requires a dockerization of compliance framework: https://github.com/prometheus/compliance/pull/46 func TestAlertCompliance(t *testing.T) { - //t.Skip("This is an interactive test, using https://github.com/prometheus/compliance/tree/main/alert_generator. This tool is not optimized for CI runs (e.g. it infinitely retries") + t.Skip("This is an interactive test, using https://github.com/prometheus/compliance/tree/main/alert_generator. This tool is not optimized for CI runs (e.g. it infinitely retries, takes 38 minutes)") t.Run("staleness ruler", func(t *testing.T) { e, err := e2e.NewDockerEnvironment("alert_compatibility") From bc5281ab6ff6b19e6ac6958ec19da6602fe10bf8 Mon Sep 17 00:00:00 2001 From: Matej Gera Date: Mon, 20 Jun 2022 14:04:07 +0200 Subject: [PATCH 13/14] Use stateful ruler and default resend delay Signed-off-by: Matej Gera --- test/e2e/compatibility_test.go | 22 +++++++++++++--------- test/e2e/e2ethanos/services.go | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/test/e2e/compatibility_test.go b/test/e2e/compatibility_test.go index b6b5c41569..9f46849928 100644 --- a/test/e2e/compatibility_test.go +++ b/test/e2e/compatibility_test.go @@ -122,7 +122,7 @@ query_tweaks: func TestAlertCompliance(t *testing.T) { t.Skip("This is an interactive test, using https://github.com/prometheus/compliance/tree/main/alert_generator. This tool is not optimized for CI runs (e.g. it infinitely retries, takes 38 minutes)") - t.Run("staleness ruler", func(t *testing.T) { + t.Run("stateful ruler", func(t *testing.T) { e, err := e2e.NewDockerEnvironment("alert_compatibility") testutil.Ok(t, err) t.Cleanup(e.Close) @@ -146,16 +146,20 @@ func TestAlertCompliance(t *testing.T) { Timeout: amTimeout, APIVersion: alert.APIv1, }, - }).InitTSDB(filepath.Join(rFuture.InternalDir(), "rulesSubDir"), []httpconfig.Config{ - { - EndpointsConfig: httpconfig.EndpointsConfig{ - StaticAddresses: []string{ - querierBuilder.InternalEndpoint("http"), + }). + // Use default resend delay and eval interval, as the compliance spec requires this. + WithResendDelay("1m"). + WithEvalInterval("1m"). + InitTSDB(filepath.Join(rFuture.InternalDir(), "rules"), []httpconfig.Config{ + { + EndpointsConfig: httpconfig.EndpointsConfig{ + StaticAddresses: []string{ + querierBuilder.InternalEndpoint("http"), + }, + Scheme: "http", }, - Scheme: "http", }, - }, - }) + }) query := querierBuilder. WithStoreAddresses(receive.InternalEndpoint("grpc")). diff --git a/test/e2e/e2ethanos/services.go b/test/e2e/e2ethanos/services.go index 8331ec9bc4..0f56e3fbcc 100644 --- a/test/e2e/e2ethanos/services.go +++ b/test/e2e/e2ethanos/services.go @@ -477,6 +477,8 @@ type RulerBuilder struct { amCfg []alert.AlertmanagerConfig replicaLabel string image string + resendDelay string + evalInterval string } // NewRulerBuilder is a Ruler future that allows extra configuration before initialization. @@ -507,6 +509,16 @@ func (r *RulerBuilder) WithReplicaLabel(replicaLabel string) *RulerBuilder { return r } +func (r *RulerBuilder) WithResendDelay(resendDelay string) *RulerBuilder { + r.resendDelay = resendDelay + return r +} + +func (r *RulerBuilder) WithEvalInterval(evalInterval string) *RulerBuilder { + r.evalInterval = evalInterval + return r +} + func (r *RulerBuilder) InitTSDB(internalRuleDir string, queryCfg []httpconfig.Config) e2e.InstrumentedRunnable { return r.initRule(internalRuleDir, queryCfg, nil) } @@ -550,6 +562,15 @@ func (r *RulerBuilder) initRule(internalRuleDir string, queryCfg []httpconfig.Co if r.replicaLabel != "" { ruleArgs["--label"] = fmt.Sprintf(`%s="%s"`, replicaLabel, r.replicaLabel) } + + if r.resendDelay != "" { + ruleArgs["--resend-delay"] = r.resendDelay + } + + if r.evalInterval != "" { + ruleArgs["--eval-interval"] = r.evalInterval + } + if remoteWriteCfg != nil { rwCfgBytes, err := yaml.Marshal(struct { RemoteWriteConfigs []*config.RemoteWriteConfig `yaml:"remote_write,omitempty"` From b7ce55746dfe51256ff1cc4dfac453e65640217b Mon Sep 17 00:00:00 2001 From: Matej Gera Date: Mon, 20 Jun 2022 14:16:29 +0200 Subject: [PATCH 14/14] Update docs Signed-off-by: Matej Gera --- docs/components/rule.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/components/rule.md b/docs/components/rule.md index 1cabaca15c..72e27cd755 100644 --- a/docs/components/rule.md +++ b/docs/components/rule.md @@ -430,7 +430,10 @@ Flags: --resend-delay=1m Minimum amount of time to wait before resending an alert to Alertmanager. --rule-file=rules/ ... Rule files that should be used by rule manager. - Can be in glob format (repeated). + Can be in glob format (repeated). Note that + rules are not automatically detected, use + SIGHUP or do HTTP POST /-/reload to re-read + them. --shipper.upload-compacted If true shipper will try to upload compacted blocks as well. Useful for migration purposes.