grafana/pkg/services/ngalert/notifier/config.go
gotjosh 528ca9134b
Alerting: Use a default configuration and periodically poll for new ones (#32851)
* Alerting: Use a default configuration and periodically poll for new ones

Use a default configuration to make sure we always start the grafana
instance. Then, regularly poll for new ones.

I've also made sure that failures to apply configuration do not stop the
Grafana server but instead keep polling until it is a success.
2021-04-13 13:02:44 +01:00

87 lines
2.3 KiB
Go

package notifier
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/grafana/alerting-api/pkg/api"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/pkg/errors"
)
func PersistTemplates(cfg *api.PostableUserConfig, path string) ([]string, bool, error) {
if len(cfg.TemplateFiles) < 1 {
return nil, false, nil
}
var templatesChanged bool
pathSet := map[string]struct{}{}
for name, content := range cfg.TemplateFiles {
if name != filepath.Base(filepath.Clean(name)) {
return nil, false, fmt.Errorf("template file name '%s' is not valid", name)
}
err := os.MkdirAll(path, 0750)
if err != nil {
return nil, false, fmt.Errorf("unable to create template directory %q: %s", path, err)
}
file := filepath.Join(path, name)
pathSet[file] = struct{}{}
// Check if the template file already exists and if it has changed
// We can safeily ignore gosec here and we've previously checked the filename is clean
// nolint:gosec
if tmpl, err := ioutil.ReadFile(file); err == nil && string(tmpl) == content {
// Templates file is the same we have, no-op and continue.
continue
} else if err != nil && !os.IsNotExist(err) {
return nil, false, err
}
if err := ioutil.WriteFile(file, []byte(content), 0644); err != nil {
return nil, false, fmt.Errorf("unable to create Alertmanager template file %q: %s", file, err)
}
// nolint:gosec
templatesChanged = true
}
// Now that we have the list of _actual_ templates, let's remove the ones that we don't need.
existingFiles, err := ioutil.ReadDir(path)
if err != nil {
log.Error("unable to read directory for deleting Alertmanager templates", "err", err, "path", path)
}
for _, existingFile := range existingFiles {
p := filepath.Join(path, existingFile.Name())
_, ok := pathSet[p]
if !ok {
templatesChanged = true
err := os.Remove(p)
if err != nil {
log.Error("unable to delete template", "err", err, "file", p)
}
}
}
paths := make([]string, 0, len(pathSet))
for path := range pathSet {
paths = append(paths, path)
}
return paths, templatesChanged, nil
}
func Load(rawConfig []byte) (*api.PostableUserConfig, error) {
cfg := &api.PostableUserConfig{}
if err := json.Unmarshal(rawConfig, cfg); err != nil {
return nil, errors.Wrap(err, "unable to parse Alertmanager configuration")
}
return cfg, nil
}