vmalert: remove notifier dependency from config (#2906)

Signed-off-by: hagen1778 <roman@victoriametrics.com>
This commit is contained in:
Roman Khavronenko 2022-07-22 13:50:41 +02:00 committed by Aliaksandr Valialkin
parent c0c9f30870
commit 970f36de17
No known key found for this signature in database
GPG Key ID: A72BEC6CD3D0DED1
5 changed files with 39 additions and 18 deletions

View File

@ -12,7 +12,6 @@ import (
"gopkg.in/yaml.v2"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/notifier"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/utils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/envtemplate"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
@ -66,7 +65,7 @@ func (g *Group) UnmarshalYAML(unmarshal func(interface{}) error) error {
}
// Validate check for internal Group or Rule configuration errors
func (g *Group) Validate(validateAnnotations, validateExpressions bool) error {
func (g *Group) Validate(validateTplFn ValidateTplFn, validateExpressions bool) error {
if g.Name == "" {
return fmt.Errorf("group name must be set")
}
@ -92,11 +91,11 @@ func (g *Group) Validate(validateAnnotations, validateExpressions bool) error {
return fmt.Errorf("invalid expression for rule %q.%q: %w", g.Name, ruleName, err)
}
}
if validateAnnotations {
if err := notifier.ValidateTemplates(r.Annotations); err != nil {
if validateTplFn != nil {
if err := validateTplFn(r.Annotations); err != nil {
return fmt.Errorf("invalid annotations for rule %q.%q: %w", g.Name, ruleName, err)
}
if err := notifier.ValidateTemplates(r.Labels); err != nil {
if err := validateTplFn(r.Labels); err != nil {
return fmt.Errorf("invalid labels for rule %q.%q: %w", g.Name, ruleName, err)
}
}
@ -169,8 +168,10 @@ func (r *Rule) Validate() error {
return checkOverflow(r.XXX, "rule")
}
type ValidateTplFn func(annotations map[string]string) error
// Parse parses rule configs from given file patterns
func Parse(pathPatterns []string, validateAnnotations, validateExpressions bool) ([]Group, error) {
func Parse(pathPatterns []string, validateTplFn ValidateTplFn, validateExpressions bool) ([]Group, error) {
var fp []string
for _, pattern := range pathPatterns {
matches, err := filepath.Glob(pattern)
@ -189,7 +190,7 @@ func Parse(pathPatterns []string, validateAnnotations, validateExpressions bool)
continue
}
for _, g := range gr {
if err := g.Validate(validateAnnotations, validateExpressions); err != nil {
if err := g.Validate(validateTplFn, validateExpressions); err != nil {
errGroup.Add(fmt.Errorf("invalid group %q in file %q: %w", g.Name, file, err))
continue
}

View File

@ -9,6 +9,7 @@ import (
"gopkg.in/yaml.v2"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/notifier"
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/templates"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
@ -21,7 +22,7 @@ func TestMain(m *testing.M) {
}
func TestParseGood(t *testing.T) {
if _, err := Parse([]string{"testdata/rules/*good.rules", "testdata/dir/*good.*"}, true, true); err != nil {
if _, err := Parse([]string{"testdata/rules/*good.rules", "testdata/dir/*good.*"}, notifier.ValidateTemplates, true); err != nil {
t.Errorf("error parsing files %s", err)
}
}
@ -65,7 +66,7 @@ func TestParseBad(t *testing.T) {
},
}
for _, tc := range testCases {
_, err := Parse(tc.path, true, true)
_, err := Parse(tc.path, notifier.ValidateTemplates, true)
if err == nil {
t.Errorf("expected to get error")
return
@ -289,8 +290,13 @@ func TestGroup_Validate(t *testing.T) {
expErr: "invalid rule",
},
}
for _, tc := range testCases {
err := tc.group.Validate(tc.validateAnnotations, tc.validateExpressions)
var validateTplFn ValidateTplFn
if tc.validateAnnotations {
validateTplFn = notifier.ValidateTemplates
}
err := tc.group.Validate(validateTplFn, tc.validateExpressions)
if err == nil {
if tc.expErr != "" {
t.Errorf("expected to get err %q; got nil insted", tc.expErr)

View File

@ -157,7 +157,7 @@ func TestUpdateWith(t *testing.T) {
func TestGroupStart(t *testing.T) {
// TODO: make parsing from string instead of file
groups, err := config.Parse([]string{"config/testdata/rules/rules1-good.rules"}, true, true)
groups, err := config.Parse([]string{"config/testdata/rules/rules1-good.rules"}, notifier.ValidateTemplates, true)
if err != nil {
t.Fatalf("failed to parse rules: %s", err)
}

View File

@ -90,7 +90,7 @@ func main() {
}
if *dryRun {
groups, err := config.Parse(*rulePath, true, true)
groups, err := config.Parse(*rulePath, notifier.ValidateTemplates, true)
if err != nil {
logger.Fatalf("failed to parse %q: %s", *rulePath, err)
}
@ -110,6 +110,11 @@ func main() {
logger.Fatalf("failed to init `external.alert.source`: %s", err)
}
var validateTplFn config.ValidateTplFn
if *validateTemplates {
validateTplFn = notifier.ValidateTemplates
}
if *replayFrom != "" || *replayTo != "" {
rw, err := remotewrite.Init(context.Background())
if err != nil {
@ -118,7 +123,7 @@ func main() {
if rw == nil {
logger.Fatalf("remoteWrite.url can't be empty in replay mode")
}
groupsCfg, err := config.Parse(*rulePath, *validateTemplates, *validateExpressions)
groupsCfg, err := config.Parse(*rulePath, validateTplFn, *validateExpressions)
if err != nil {
logger.Fatalf("cannot parse configuration file: %s", err)
}
@ -140,7 +145,7 @@ func main() {
logger.Fatalf("failed to init: %s", err)
}
logger.Infof("reading rules configuration file from %q", strings.Join(*rulePath, ";"))
groupsCfg, err := config.Parse(*rulePath, *validateTemplates, *validateExpressions)
groupsCfg, err := config.Parse(*rulePath, validateTplFn, *validateExpressions)
if err != nil {
logger.Fatalf("cannot parse configuration file: %s", err)
}
@ -285,6 +290,11 @@ func configReload(ctx context.Context, m *manager, groupsCfg []config.Group, sig
defer ticker.Stop()
}
var validateTplFn config.ValidateTplFn
if *validateTemplates {
validateTplFn = notifier.ValidateTemplates
}
// init reload metrics with positive values to improve alerting conditions
configSuccess.Set(1)
configTimestamp.Set(fasttime.UnixTimestamp())
@ -314,7 +324,7 @@ func configReload(ctx context.Context, m *manager, groupsCfg []config.Group, sig
logger.Errorf("failed to load new templates: %s", err)
continue
}
newGroupsCfg, err := config.Parse(*rulePath, *validateTemplates, *validateExpressions)
newGroupsCfg, err := config.Parse(*rulePath, validateTplFn, *validateExpressions)
if err != nil {
configReloadErrors.Inc()
configSuccess.Set(0)

View File

@ -68,7 +68,7 @@ func TestManagerUpdateConcurrent(t *testing.T) {
defer wg.Done()
for i := 0; i < iterations; i++ {
rnd := rand.Intn(len(paths))
cfg, err := config.Parse([]string{paths[rnd]}, true, true)
cfg, err := config.Parse([]string{paths[rnd]}, notifier.ValidateTemplates, true)
if err != nil { // update can fail and this is expected
continue
}
@ -231,7 +231,7 @@ func TestManagerUpdate(t *testing.T) {
t.Fatalf("failed to complete initial rules update: %s", err)
}
cfgUpdate, err := config.Parse([]string{tc.updatePath}, true, true)
cfgUpdate, err := config.Parse([]string{tc.updatePath}, notifier.ValidateTemplates, true)
if err == nil { // update can fail and that's expected
_ = m.update(ctx, cfgUpdate, false)
}
@ -329,7 +329,11 @@ func TestManagerUpdateNegative(t *testing.T) {
func loadCfg(t *testing.T, path []string, validateAnnotations, validateExpressions bool) []config.Group {
t.Helper()
cfg, err := config.Parse(path, validateAnnotations, validateExpressions)
var validateTplFn config.ValidateTplFn
if validateAnnotations {
validateTplFn = notifier.ValidateTemplates
}
cfg, err := config.Parse(path, validateTplFn, validateExpressions)
if err != nil {
t.Fatal(err)
}