2022-08-01 11:17:42 -05:00
|
|
|
package alerting
|
2022-07-14 16:53:13 -05:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"io/fs"
|
2022-08-10 08:37:51 -05:00
|
|
|
"os"
|
2022-07-14 16:53:13 -05:00
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
type rulesConfigReader struct {
|
|
|
|
log log.Logger
|
|
|
|
}
|
|
|
|
|
|
|
|
func newRulesConfigReader(logger log.Logger) rulesConfigReader {
|
|
|
|
return rulesConfigReader{
|
|
|
|
log: logger,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-01 11:17:42 -05:00
|
|
|
func (cr *rulesConfigReader) readConfig(ctx context.Context, path string) ([]*AlertingFile, error) {
|
|
|
|
var alertFiles []*AlertingFile
|
|
|
|
cr.log.Debug("looking for alerting provisioning files", "path", path)
|
2022-07-14 16:53:13 -05:00
|
|
|
|
2022-08-11 06:21:12 -05:00
|
|
|
files, err := os.ReadDir(path)
|
2022-07-14 16:53:13 -05:00
|
|
|
if err != nil {
|
2022-08-01 11:17:42 -05:00
|
|
|
cr.log.Error("can't read alerting provisioning files from directory", "path", path, "error", err)
|
|
|
|
return alertFiles, nil
|
2022-07-14 16:53:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, file := range files {
|
2022-08-01 11:17:42 -05:00
|
|
|
cr.log.Debug("parsing alerting provisioning file", "path", path, "file.Name", file.Name())
|
2022-07-14 16:53:13 -05:00
|
|
|
if !cr.isYAML(file.Name()) && !cr.isJSON(file.Name()) {
|
2022-09-21 09:48:39 -05:00
|
|
|
cr.log.Warn(fmt.Sprintf("file has invalid suffix '%s' (.yaml,.yml,.json accepted), skipping", file.Name()))
|
|
|
|
continue
|
2022-07-14 16:53:13 -05:00
|
|
|
}
|
2022-08-01 11:17:42 -05:00
|
|
|
alertFileV1, err := cr.parseConfig(path, file)
|
2022-07-14 16:53:13 -05:00
|
|
|
if err != nil {
|
2022-08-01 11:17:42 -05:00
|
|
|
return nil, fmt.Errorf("failure to parse file %s: %w", file.Name(), err)
|
2022-07-14 16:53:13 -05:00
|
|
|
}
|
2022-08-01 11:17:42 -05:00
|
|
|
if alertFileV1 != nil {
|
|
|
|
alertFileV1.Filename = file.Name()
|
|
|
|
alertFile, err := alertFileV1.MapToModel()
|
2022-07-14 16:53:13 -05:00
|
|
|
if err != nil {
|
2022-08-01 11:17:42 -05:00
|
|
|
return nil, fmt.Errorf("failure to map file %s: %w", alertFileV1.Filename, err)
|
2022-07-14 16:53:13 -05:00
|
|
|
}
|
2022-08-01 11:17:42 -05:00
|
|
|
alertFiles = append(alertFiles, &alertFile)
|
2022-07-14 16:53:13 -05:00
|
|
|
}
|
|
|
|
}
|
2022-08-01 11:17:42 -05:00
|
|
|
return alertFiles, nil
|
2022-07-14 16:53:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (cr *rulesConfigReader) isYAML(file string) bool {
|
|
|
|
return strings.HasSuffix(file, ".yaml") || strings.HasSuffix(file, ".yml")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cr *rulesConfigReader) isJSON(file string) bool {
|
|
|
|
return strings.HasSuffix(file, ".json")
|
|
|
|
}
|
|
|
|
|
2022-08-11 06:21:12 -05:00
|
|
|
func (cr *rulesConfigReader) parseConfig(path string, file fs.DirEntry) (*AlertingFileV1, error) {
|
2022-07-14 16:53:13 -05:00
|
|
|
filename, _ := filepath.Abs(filepath.Join(path, file.Name()))
|
|
|
|
// nolint:gosec
|
|
|
|
// We can ignore the gosec G304 warning on this one because `filename` comes from ps.Cfg.ProvisioningPath
|
2022-08-10 08:37:51 -05:00
|
|
|
yamlFile, err := os.ReadFile(filename)
|
2022-07-14 16:53:13 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-08-01 11:17:42 -05:00
|
|
|
var cfg *AlertingFileV1
|
2022-07-14 16:53:13 -05:00
|
|
|
err = yaml.Unmarshal(yamlFile, &cfg)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return cfg, nil
|
|
|
|
}
|