config: Support "include" directive
With this directive other configuration files can be imported into the main config. Can be useful for keeping secrets out of the latter. Closes: https://todo.xenrox.net/~xenrox/ntfy-alertmanager/23
This commit is contained in:
parent
8ea629264d
commit
6c2521eeca
2 changed files with 326 additions and 294 deletions
|
@ -1,3 +1,8 @@
|
|||
# Absolute path to another scfg configuration file which will be included.
|
||||
# This directive can be specified multiple times in the main configuration,
|
||||
# but only the last occurrence of a setting will be used. Settings from
|
||||
# the main configuration will take precedence.
|
||||
include /etc/ntfy-alertmanager/ntfy.scfg
|
||||
# Public facing base URL of the service (e.g. https://ntfy-alertmanager.xenrox.net)
|
||||
# This setting is required for the "Silence" feature.
|
||||
base-url https://ntfy-alertmanager.xenrox.net
|
||||
|
|
615
config/config.go
615
config/config.go
|
@ -21,6 +21,7 @@ const (
|
|||
|
||||
// Config is the configuration of the bridge.
|
||||
type Config struct {
|
||||
Include string
|
||||
BaseURL string
|
||||
HTTPAddress string
|
||||
LogLevel string
|
||||
|
@ -82,6 +83,308 @@ type resolvedConfig struct {
|
|||
Priority string
|
||||
}
|
||||
|
||||
func parseBlock(block scfg.Block, config *Config) error {
|
||||
d := block.Get("log-level")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.LogLevel); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = block.Get("log-format")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.LogFormat); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = block.Get("http-address")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.HTTPAddress); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = block.Get("base-url")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.BaseURL); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = block.Get("alert-mode")
|
||||
if d != nil {
|
||||
var mode string
|
||||
if err := d.ParseParams(&mode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch strings.ToLower(mode) {
|
||||
case "single":
|
||||
config.AlertMode = Single
|
||||
|
||||
case "multi":
|
||||
config.AlertMode = Multi
|
||||
|
||||
default:
|
||||
return fmt.Errorf("%q directive: illegal mode %q", d.Name, mode)
|
||||
}
|
||||
}
|
||||
|
||||
d = block.Get("user")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.User); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = block.Get("password")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Password); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
labelsDir := block.Get("labels")
|
||||
if labelsDir != nil {
|
||||
d = labelsDir.Children.Get("order")
|
||||
if d != nil {
|
||||
var order string
|
||||
if err := d.ParseParams(&order); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config.Labels.Order = strings.Split(order, ",")
|
||||
}
|
||||
|
||||
labels := make(map[string]labelConfig)
|
||||
for _, labelName := range config.Labels.Order {
|
||||
for _, labelDir := range labelsDir.Children.GetAll(labelName) {
|
||||
labelConfig := new(labelConfig)
|
||||
var name string
|
||||
|
||||
if err := labelDir.ParseParams(&name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
d = labelDir.Children.Get("priority")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&labelConfig.Priority); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = labelDir.Children.Get("tags")
|
||||
if d != nil {
|
||||
var tags string
|
||||
if err := d.ParseParams(&tags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
labelConfig.Tags = strings.Split(tags, ",")
|
||||
}
|
||||
|
||||
d = labelDir.Children.Get("icon")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&labelConfig.Icon); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = labelDir.Children.Get("email-address")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&labelConfig.EmailAddress); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = labelDir.Children.Get("call")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&labelConfig.Call); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
labels[fmt.Sprintf("%s:%s", labelName, name)] = *labelConfig
|
||||
}
|
||||
}
|
||||
|
||||
config.Labels.Label = labels
|
||||
}
|
||||
|
||||
ntfyDir := block.Get("ntfy")
|
||||
if ntfyDir != nil {
|
||||
d = ntfyDir.Children.Get("topic")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Ntfy.Topic); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = ntfyDir.Children.Get("user")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Ntfy.User); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = ntfyDir.Children.Get("password")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Ntfy.Password); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = ntfyDir.Children.Get("access-token")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Ntfy.AccessToken); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = ntfyDir.Children.Get("certificate-fingerprint")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Ntfy.CertFingerprint); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// hex.EncodeToString outputs a lower case string
|
||||
config.Ntfy.CertFingerprint = strings.ToLower(strings.ReplaceAll(config.Ntfy.CertFingerprint, ":", ""))
|
||||
}
|
||||
|
||||
d = ntfyDir.Children.Get("email-address")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Ntfy.EmailAddress); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = ntfyDir.Children.Get("call")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Ntfy.Call); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cacheDir := block.Get("cache")
|
||||
if cacheDir != nil {
|
||||
d = cacheDir.Children.Get("type")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Cache.Type); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var durationString string
|
||||
d = cacheDir.Children.Get("duration")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&durationString); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
duration, err := time.ParseDuration(durationString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config.Cache.Duration = duration
|
||||
}
|
||||
|
||||
// memory
|
||||
var cleanupIntervalString string
|
||||
d = cacheDir.Children.Get("cleanup-interval")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&cleanupIntervalString); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
interval, err := time.ParseDuration(cleanupIntervalString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config.Cache.CleanupInterval = interval
|
||||
}
|
||||
|
||||
// redis
|
||||
d = cacheDir.Children.Get("redis-url")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Cache.RedisURL); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
amDir := block.Get("alertmanager")
|
||||
if amDir != nil {
|
||||
var durationString string
|
||||
d = amDir.Children.Get("silence-duration")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&durationString); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
duration, err := time.ParseDuration(durationString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config.Am.SilenceDuration = duration
|
||||
}
|
||||
|
||||
d = amDir.Children.Get("user")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Am.User); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = amDir.Children.Get("password")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Am.Password); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = amDir.Children.Get("url")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Am.URL); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolvedDir := block.Get("resolved")
|
||||
if resolvedDir != nil {
|
||||
d = resolvedDir.Children.Get("tags")
|
||||
if d != nil {
|
||||
var tags string
|
||||
if err := d.ParseParams(&tags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
config.Resolved.Tags = strings.Split(tags, ",")
|
||||
}
|
||||
|
||||
d = resolvedDir.Children.Get("icon")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Resolved.Icon); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
d = resolvedDir.Children.Get("priority")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Resolved.Priority); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadConfig reads an scfg formatted file and returns the configuration struct.
|
||||
func ReadConfig(path string) (*Config, error) {
|
||||
cfg, err := scfg.Load(path)
|
||||
|
@ -103,326 +406,50 @@ func ReadConfig(path string) (*Config, error) {
|
|||
// redis
|
||||
config.Cache.RedisURL = "redis://localhost:6379"
|
||||
|
||||
d := cfg.Get("log-level")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.LogLevel); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
d = cfg.Get("log-format")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.LogFormat); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
d = cfg.Get("http-address")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.HTTPAddress); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
d = cfg.Get("base-url")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.BaseURL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
d = cfg.Get("alert-mode")
|
||||
if d != nil {
|
||||
var mode string
|
||||
if err := d.ParseParams(&mode); err != nil {
|
||||
includeDirs := cfg.GetAll("include")
|
||||
for _, d := range includeDirs {
|
||||
var includePath string
|
||||
if err := d.ParseParams(&includePath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch strings.ToLower(mode) {
|
||||
case "single":
|
||||
config.AlertMode = Single
|
||||
block, err := scfg.Load(includePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot load included config file %q: %v", includePath, err)
|
||||
}
|
||||
|
||||
case "multi":
|
||||
config.AlertMode = Multi
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("%q directive: illegal mode %q", d.Name, mode)
|
||||
if err := parseBlock(block, config); err != nil {
|
||||
return nil, fmt.Errorf("cannot parse included config file %q: %v", includePath, err)
|
||||
}
|
||||
}
|
||||
|
||||
d = cfg.Get("user")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.User); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
d = cfg.Get("password")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Password); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = parseBlock(cfg, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check settings
|
||||
if (config.Password != "" && config.User == "") ||
|
||||
(config.Password == "" && config.User != "") {
|
||||
return nil, errors.New("user and password have to be set together")
|
||||
}
|
||||
|
||||
labelsDir := cfg.Get("labels")
|
||||
if labelsDir != nil {
|
||||
d = labelsDir.Children.Get("order")
|
||||
if d != nil {
|
||||
var order string
|
||||
if err := d.ParseParams(&order); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.Labels.Order = strings.Split(order, ",")
|
||||
}
|
||||
|
||||
labels := make(map[string]labelConfig)
|
||||
for _, labelName := range config.Labels.Order {
|
||||
for _, labelDir := range labelsDir.Children.GetAll(labelName) {
|
||||
labelConfig := new(labelConfig)
|
||||
var name string
|
||||
|
||||
if err := labelDir.ParseParams(&name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d = labelDir.Children.Get("priority")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&labelConfig.Priority); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
d = labelDir.Children.Get("tags")
|
||||
if d != nil {
|
||||
var tags string
|
||||
if err := d.ParseParams(&tags); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
labelConfig.Tags = strings.Split(tags, ",")
|
||||
}
|
||||
|
||||
d = labelDir.Children.Get("icon")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&labelConfig.Icon); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
d = labelDir.Children.Get("email-address")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&labelConfig.EmailAddress); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
d = labelDir.Children.Get("call")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&labelConfig.Call); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
labels[fmt.Sprintf("%s:%s", labelName, name)] = *labelConfig
|
||||
}
|
||||
}
|
||||
|
||||
config.Labels.Label = labels
|
||||
}
|
||||
|
||||
ntfyDir := cfg.Get("ntfy")
|
||||
if ntfyDir == nil {
|
||||
return nil, fmt.Errorf("%q directive missing", "ntfy")
|
||||
}
|
||||
|
||||
d = ntfyDir.Children.Get("topic")
|
||||
if d == nil {
|
||||
if config.Ntfy.Topic == "" {
|
||||
return nil, fmt.Errorf("%q missing from %q directive", "topic", "ntfy")
|
||||
}
|
||||
if err := d.ParseParams(&config.Ntfy.Topic); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d = ntfyDir.Children.Get("user")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Ntfy.User); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
d = ntfyDir.Children.Get("password")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Ntfy.Password); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if (config.Ntfy.Password != "" && config.Ntfy.User == "") ||
|
||||
(config.Ntfy.Password == "" && config.Ntfy.User != "") {
|
||||
return nil, errors.New("ntfy: user and password have to be set together")
|
||||
}
|
||||
|
||||
d = ntfyDir.Children.Get("access-token")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Ntfy.AccessToken); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if config.Ntfy.User != "" && config.Ntfy.AccessToken != "" {
|
||||
return nil, errors.New("ntfy: cannot use both an access-token and a user/password at the same time")
|
||||
}
|
||||
|
||||
d = ntfyDir.Children.Get("certificate-fingerprint")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Ntfy.CertFingerprint); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// hex.EncodeToString outputs a lower case string
|
||||
config.Ntfy.CertFingerprint = strings.ToLower(strings.ReplaceAll(config.Ntfy.CertFingerprint, ":", ""))
|
||||
}
|
||||
|
||||
d = ntfyDir.Children.Get("email-address")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Ntfy.EmailAddress); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
d = ntfyDir.Children.Get("call")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Ntfy.Call); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
cacheDir := cfg.Get("cache")
|
||||
|
||||
if cacheDir != nil {
|
||||
d = cacheDir.Children.Get("type")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Cache.Type); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var durationString string
|
||||
d = cacheDir.Children.Get("duration")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&durationString); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
duration, err := time.ParseDuration(durationString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.Cache.Duration = duration
|
||||
}
|
||||
|
||||
// memory
|
||||
var cleanupIntervalString string
|
||||
d = cacheDir.Children.Get("cleanup-interval")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&cleanupIntervalString); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
interval, err := time.ParseDuration(cleanupIntervalString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.Cache.CleanupInterval = interval
|
||||
}
|
||||
|
||||
// redis
|
||||
d = cacheDir.Children.Get("redis-url")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Cache.RedisURL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
amDir := cfg.Get("alertmanager")
|
||||
|
||||
if amDir != nil {
|
||||
var durationString string
|
||||
d = amDir.Children.Get("silence-duration")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&durationString); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
duration, err := time.ParseDuration(durationString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.Am.SilenceDuration = duration
|
||||
}
|
||||
|
||||
d = amDir.Children.Get("user")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Am.User); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
d = amDir.Children.Get("password")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Am.Password); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if (config.Am.Password != "" && config.Am.User == "") ||
|
||||
(config.Am.Password == "" && config.Am.User != "") {
|
||||
return nil, errors.New("alertmanager: user and password have to be set together")
|
||||
}
|
||||
|
||||
d = amDir.Children.Get("url")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Am.URL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolvedDir := cfg.Get("resolved")
|
||||
if resolvedDir != nil {
|
||||
d = resolvedDir.Children.Get("tags")
|
||||
if d != nil {
|
||||
var tags string
|
||||
if err := d.ParseParams(&tags); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.Resolved.Tags = strings.Split(tags, ",")
|
||||
}
|
||||
|
||||
d = resolvedDir.Children.Get("icon")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Resolved.Icon); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
d = resolvedDir.Children.Get("priority")
|
||||
if d != nil {
|
||||
if err := d.ParseParams(&config.Resolved.Priority); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if (config.Am.Password != "" && config.Am.User == "") ||
|
||||
(config.Am.Password == "" && config.Am.User != "") {
|
||||
return nil, errors.New("alertmanager: user and password have to be set together")
|
||||
}
|
||||
|
||||
return config, nil
|
||||
|
|
Loading…
Add table
Reference in a new issue