diff --git a/config/config.go b/config/config.go index 467ae662c..273377ab6 100644 --- a/config/config.go +++ b/config/config.go @@ -18,6 +18,7 @@ import ( var ( patJobName = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_-]*$`) patFileSDName = regexp.MustCompile(`^[^*]*(\*[^/]*)?\.(json|yml|yaml|JSON|YML|YAML)$`) + patRulePath = regexp.MustCompile(`^[^*]*(\*[^/]*)?$`) ) // Load parses the YAML input s into a Config. @@ -112,6 +113,11 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error { if err := unmarshal(&c.DefaultedConfig); err != nil { return err } + for _, rf := range c.RuleFiles { + if !patRulePath.MatchString(rf) { + return fmt.Errorf("invalid rule file path %q", rf) + } + } // Do global overrides and validate unique names. jobNames := map[string]struct{}{} for _, scfg := range c.ScrapeConfigs { diff --git a/config/config_test.go b/config/config_test.go index ad21d3e0c..61aeb7f84 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -27,6 +27,7 @@ var expectedConf = &Config{DefaultedConfig{ RuleFiles: []string{ "first.rules", "second.rules", + "my/*.rules", }, ScrapeConfigs: []*ScrapeConfig{ @@ -151,6 +152,9 @@ var expectedErrors = []struct { }, { filename: "regex.bad.yml", errMsg: "error parsing regexp", + }, { + filename: "rules.bad.yml", + errMsg: "invalid rule file path", }, } @@ -159,6 +163,7 @@ func TestBadConfigs(t *testing.T) { _, err := LoadFromFile("testdata/" + ee.filename) if err == nil { t.Errorf("Expected error parsing %s but got none", ee.filename) + continue } if !strings.Contains(err.Error(), ee.errMsg) { t.Errorf("Expected error for %s to contain %q but got: %s", ee.filename, ee.errMsg, err) diff --git a/config/testdata/conf.good.yml b/config/testdata/conf.good.yml index 6af1db01c..831006e2e 100644 --- a/config/testdata/conf.good.yml +++ b/config/testdata/conf.good.yml @@ -11,6 +11,7 @@ global: rule_files: - "first.rules" - "second.rules" + - "my/*.rules" scrape_configs: - job_name: prometheus diff --git a/config/testdata/rules.bad.yml b/config/testdata/rules.bad.yml new file mode 100644 index 000000000..b812401e5 --- /dev/null +++ b/config/testdata/rules.bad.yml @@ -0,0 +1,3 @@ +rule_files: + - 'my_rule' # fine + - 'my/*/rule' # bad diff --git a/rules/manager.go b/rules/manager.go index bb7ba7aed..a901991f0 100644 --- a/rules/manager.go +++ b/rules/manager.go @@ -16,6 +16,7 @@ package rules import ( "fmt" "io/ioutil" + "path/filepath" "strings" "sync" "time" @@ -281,7 +282,16 @@ func (m *Manager) ApplyConfig(conf *config.Config) { copy(rulesSnapshot, m.rules) m.rules = m.rules[:0] - if err := m.loadRuleFiles(conf.RuleFiles...); err != nil { + var files []string + for _, pat := range conf.RuleFiles { + fs, err := filepath.Glob(pat) + if err != nil { + // The only error can be a bad pattern. + log.Errorf("Error retrieving rule files for %s: %s", pat, err) + } + files = append(files, fs...) + } + if err := m.loadRuleFiles(files...); err != nil { // If loading the new rules failed, restore the old rule set. m.rules = rulesSnapshot log.Errorf("Error loading rules, previous rule set restored: %s", err)