New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added alert compliance test for Thanos #5315
Changes from 5 commits
8468a90
8fc03b9
fbb1b1d
c11a4c2
fa27046
d35e0dd
bf3a31c
7418254
1b9e19b
e40d25e
c13a975
d786eac
fb87286
bc5281a
b7ce557
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,8 @@ | |
package e2e_test | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
|
@@ -12,10 +14,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 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.") | ||
|
@@ -24,7 +32,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 +61,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)) | ||
|
@@ -70,24 +78,28 @@ 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"))) | ||
t.Log(stdout, stderr) | ||
testutil.Ok(t, err) | ||
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.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) | ||
[]byte(promQLCompatConfig(prom, querySidecar, []string{"prometheus"})), os.ModePerm)) | ||
|
||
testutil.Ok(t, compliance.Exec(e2e.NewCommand( | ||
"/promql-compliance-tester", | ||
"-config-file", filepath.Join(compliance.InternalDir(), "sidecar.yaml"), | ||
"-config-file", "/promql-test-queries.yml", | ||
))) | ||
}) | ||
} | ||
|
||
func promLabelsPromQLConfig(reference *e2edb.Prometheus, target e2e.Runnable, dropLabels []string) string { | ||
// 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") + `' | ||
|
||
|
@@ -105,3 +117,81 @@ query_tweaks: | |
return ret | ||
}() | ||
} | ||
|
||
// 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") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we are using Thanos receiver in this case, the alerts will have the tenant label. If I remember correctly, the alerts compliance test requires the exact match of alerts labels. So maybe we need to configure the Querier to ignore the tenant label |
||
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{}, | ||
bwplotka marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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", | ||
}, | ||
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, 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 `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") + `' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see stateless ruler being set as one endpoint of the Thanos Querier so I guess we cannot read anything from the Querier? Maybe we can use ruler's endpoint directly? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point! |
||
alert_reception_server_port: 8080 | ||
alert_message_parser: default | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about making this similar to https://github.com/thanos-io/thanos/blob/main/test/e2e/e2ethanos/services.go#L1058? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't mind any, happy to change. |
||
` | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be great to have another test case for TSDB ruler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same code is used, but yes - you played with it? Do you have it rdy? (we could add in another PR)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have the code now. Happy to add it in another pr once this gets merged.