ntfy-alertmanager/config/config.go
Thorben Günther a9fa7e4b23
config: Switch default values of alert mode and cache type
By default alerts will no longer be split apart and any caching
functionality will be disabled. With this the behaviour will be closer
to what the user has configured in Alertmanger/Prometheus itself.
2023-07-12 19:17:47 +02:00

401 lines
8.3 KiB
Go

// Package config defines the configuration file.
package config
import (
"errors"
"fmt"
"strings"
"time"
"git.sr.ht/~emersion/go-scfg"
)
// AlertMode determines if alerts grouped by Alertmanager are being kept together.
type AlertMode int
// The different modes for AlertMode.
const (
Single AlertMode = iota
Multi
)
// Config is the configuration of the bridge.
type Config struct {
BaseURL string
HTTPAddress string
LogLevel string
AlertMode AlertMode
User string
Password string
Ntfy ntfyConfig
Labels labels
Cache CacheConfig
Am alertmanagerConfig
Resolved resolvedConfig
}
type ntfyConfig struct {
Topic string
User string
Password string
AccessToken string
EmailAddress string
Call string
}
type labels struct {
Order []string
Label map[string]labelConfig
}
type labelConfig struct {
Priority string
Tags []string
Icon string
EmailAddress string
Call string
}
// CacheConfig is the configuration of the cache.
type CacheConfig struct {
// shared settings
Type string
Duration time.Duration
// memory settings
CleanupInterval time.Duration
// redis settings
RedisURL string
}
type alertmanagerConfig struct {
User string
Password string
SilenceDuration time.Duration
URL string
}
type resolvedConfig struct {
Tags []string
Icon string
}
// ReadConfig reads an scfg formatted file and returns the configuration struct.
func ReadConfig(path string) (*Config, error) {
cfg, err := scfg.Load(path)
if err != nil {
return nil, err
}
config := new(Config)
// Set default values
config.HTTPAddress = "127.0.0.1:8080"
config.LogLevel = "info"
config.AlertMode = Multi
config.Cache.Type = "disabled"
config.Cache.Duration = time.Hour * 24
// memory
config.Cache.CleanupInterval = time.Hour
// 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("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 {
return nil, err
}
switch strings.ToLower(mode) {
case "single":
config.AlertMode = Single
case "multi":
config.AlertMode = Multi
default:
return nil, fmt.Errorf("%q directive: illegal mode %q", d.Name, mode)
}
}
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
}
}
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 {
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("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
}
}
}
return config, nil
}