diff --git a/cmd/thanos/testdata/rules-files/valid_1.yaml b/cmd/thanos/testdata/rules-files/valid_1.yaml new file mode 100644 index 0000000000..fb75e799e2 --- /dev/null +++ b/cmd/thanos/testdata/rules-files/valid_1.yaml @@ -0,0 +1,18 @@ +groups: + - name: test-alert-group + partial_response_strategy: "warn" + interval: 2m + rules: + - alert: TestAlert + expr: 1 + labels: + key: value + annotations: + key: value + + - name: test-rule-group + partial_response_strategy: "warn" + interval: 2m + rules: + - record: test_metric + expr: 1 diff --git a/cmd/thanos/testdata/rules-files/valid_2.yaml b/cmd/thanos/testdata/rules-files/valid_2.yaml new file mode 100644 index 0000000000..fb75e799e2 --- /dev/null +++ b/cmd/thanos/testdata/rules-files/valid_2.yaml @@ -0,0 +1,18 @@ +groups: + - name: test-alert-group + partial_response_strategy: "warn" + interval: 2m + rules: + - alert: TestAlert + expr: 1 + labels: + key: value + annotations: + key: value + + - name: test-rule-group + partial_response_strategy: "warn" + interval: 2m + rules: + - record: test_metric + expr: 1 diff --git a/cmd/thanos/tools.go b/cmd/thanos/tools.go index c0c9b04ed8..e916da8ed0 100644 --- a/cmd/thanos/tools.go +++ b/cmd/thanos/tools.go @@ -5,11 +5,13 @@ package main import ( "os" + "path/filepath" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/oklog/run" "github.com/opentracing/opentracing-go" + "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/thanos-io/thanos/pkg/errutil" "github.com/thanos-io/thanos/pkg/extkingpin" @@ -25,7 +27,7 @@ func registerTools(app *extkingpin.App) { func registerCheckRules(app extkingpin.AppClause) { cmd := app.Command("rules-check", "Check if the rule files are valid or not.") - ruleFiles := cmd.Flag("rules", "The rule files glob to check (repeated).").Required().ExistingFiles() + ruleFiles := cmd.Flag("rules", "The rule files glob to check (repeated).").Required().Strings() cmd.Setup(func(g *run.Group, logger log.Logger, reg *prometheus.Registry, _ opentracing.Tracer, _ <-chan struct{}, _ bool) error { // Dummy actor to immediately kill the group after the run function returns. @@ -34,31 +36,42 @@ func registerCheckRules(app extkingpin.AppClause) { }) } -func checkRulesFiles(logger log.Logger, files *[]string) error { +func checkRulesFiles(logger log.Logger, patterns *[]string) error { var failed errutil.MultiError - for _, fn := range *files { - level.Info(logger).Log("msg", "checking", "filename", fn) - f, err := os.Open(fn) - if err != nil { + for _, p := range *patterns { + level.Info(logger).Log("msg", "checking", "pattern", p) + matches, err := filepath.Glob(p) + if err != nil || matches == nil { + err = errors.New("matching file not found") level.Error(logger).Log("result", "FAILED", "error", err) level.Info(logger).Log() failed.Add(err) continue } - defer func() { _ = f.Close() }() + for _, fn := range matches { + level.Info(logger).Log("msg", "checking", "filename", fn) + f, er := os.Open(fn) + if er != nil { + level.Error(logger).Log("result", "FAILED", "error", er) + level.Info(logger).Log() + failed.Add(err) + continue + } + defer func() { _ = f.Close() }() - n, errs := rules.ValidateAndCount(f) - if errs.Err() != nil { - level.Error(logger).Log("result", "FAILED") - for _, e := range errs { - level.Error(logger).Log("error", e.Error()) - failed.Add(e) + n, errs := rules.ValidateAndCount(f) + if errs.Err() != nil { + level.Error(logger).Log("result", "FAILED") + for _, e := range errs { + level.Error(logger).Log("error", e.Error()) + failed.Add(e) + } + level.Info(logger).Log() + continue } - level.Info(logger).Log() - continue + level.Info(logger).Log("result", "SUCCESS", "rules found", n) } - level.Info(logger).Log("result", "SUCCESS", "rules found", n) } return failed.Err() } diff --git a/cmd/thanos/tools_test.go b/cmd/thanos/tools_test.go index 8a5792f180..512f788c90 100644 --- a/cmd/thanos/tools_test.go +++ b/cmd/thanos/tools_test.go @@ -29,3 +29,18 @@ func Test_CheckRules(t *testing.T) { testutil.NotOk(t, checkRulesFiles(logger, &fn), "expected err for file %s", fn) } } + +func Test_CheckRules_Glob(t *testing.T) { + // regex path + files := &[]string{"./testdata/rules-files/valid*.yaml"} + logger := log.NewNopLogger() + testutil.Ok(t, checkRulesFiles(logger, files)) + + // direct path + files = &[]string{"./testdata/rules-files/valid.yaml"} + testutil.Ok(t, checkRulesFiles(logger, files)) + + // invalid path + files = &[]string{"./testdata/rules-files/*.yamlaaa"} + testutil.NotOk(t, checkRulesFiles(logger, files), "expected err for file %s", files) +}