config_reloader.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. package config
  2. import (
  3. "os"
  4. "path/filepath"
  5. "reflect"
  6. "regexp"
  7. "github.com/prometheus/client_golang/prometheus"
  8. "github.com/prometheus/client_golang/prometheus/promauto"
  9. log "github.com/sirupsen/logrus"
  10. "github.com/spf13/viper"
  11. )
  12. var (
  13. metricConfigActionCount = promauto.NewGauge(prometheus.GaugeOpts{
  14. Name: "olivetin_config_action_count",
  15. Help: "The number of actions in the config file",
  16. })
  17. metricConfigReloadedCount = promauto.NewCounter(prometheus.CounterOpts{
  18. Name: "olivetin_config_reloaded_count",
  19. Help: "The number of times the config has been reloaded",
  20. })
  21. listeners []func()
  22. )
  23. func AddListener(l func()) {
  24. listeners = append(listeners, l)
  25. }
  26. func Reload(cfg *Config) {
  27. if err := viper.UnmarshalExact(&cfg, viper.DecodeHook(envDecodeHookFunc)); err != nil {
  28. log.Errorf("Config unmarshal error %+v", err)
  29. os.Exit(1)
  30. }
  31. metricConfigReloadedCount.Inc()
  32. metricConfigActionCount.Set(float64(len(cfg.Actions)))
  33. cfg.SetDir(filepath.Dir(viper.ConfigFileUsed()))
  34. cfg.Sanitize()
  35. for _, l := range listeners {
  36. l()
  37. }
  38. }
  39. var envRegex = regexp.MustCompile(`\${{ *?(\S+) *?}}`)
  40. func envDecodeHookFunc(from reflect.Value, to reflect.Value) (any, error) {
  41. if from.Kind() != reflect.String {
  42. return from.Interface(), nil
  43. }
  44. input := from.Interface().(string)
  45. output := envRegex.ReplaceAllStringFunc(input, func(match string) string {
  46. submatches := envRegex.FindStringSubmatch(match)
  47. key := submatches[1]
  48. val, set := os.LookupEnv(key)
  49. if !set {
  50. log.Warnf("Config file references unset environment variable: \"%s\"", key)
  51. }
  52. return val
  53. })
  54. return output, nil
  55. }