config: Move to own package
This commit is contained in:
parent
e66cc0d858
commit
c70b82e9ab
4 changed files with 113 additions and 105 deletions
|
@ -1,4 +1,5 @@
|
||||||
package main
|
// Package config defines the configuration file.
|
||||||
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -9,32 +10,37 @@ import (
|
||||||
"git.sr.ht/~emersion/go-scfg"
|
"git.sr.ht/~emersion/go-scfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
type alertMode int
|
// AlertMode determines if alerts grouped by Alertmanager are being kept together.
|
||||||
|
type AlertMode int
|
||||||
|
|
||||||
|
// The different modes for AlertMode.
|
||||||
const (
|
const (
|
||||||
single alertMode = iota
|
Single AlertMode = iota
|
||||||
multi
|
Multi
|
||||||
)
|
)
|
||||||
|
|
||||||
type cacheType int
|
// CacheType is the type of cache that well be used.
|
||||||
|
type CacheType int
|
||||||
|
|
||||||
|
// The different types of caches.
|
||||||
const (
|
const (
|
||||||
memory cacheType = iota
|
Memory CacheType = iota
|
||||||
redis
|
Redis
|
||||||
)
|
)
|
||||||
|
|
||||||
type config struct {
|
// Config is the configuration of the bridge.
|
||||||
|
type Config struct {
|
||||||
BaseURL string
|
BaseURL string
|
||||||
HTTPAddress string
|
HTTPAddress string
|
||||||
LogLevel string
|
LogLevel string
|
||||||
alertMode alertMode
|
AlertMode AlertMode
|
||||||
User string
|
User string
|
||||||
Password string
|
Password string
|
||||||
ntfy ntfyConfig
|
Ntfy ntfyConfig
|
||||||
labels labels
|
Labels labels
|
||||||
cache cacheConfig
|
Cache cacheConfig
|
||||||
am alertmanagerConfig
|
Am alertmanagerConfig
|
||||||
resolved resolvedConfig
|
Resolved resolvedConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type ntfyConfig struct {
|
type ntfyConfig struct {
|
||||||
|
@ -42,8 +48,8 @@ type ntfyConfig struct {
|
||||||
User string
|
User string
|
||||||
Password string
|
Password string
|
||||||
AccessToken string
|
AccessToken string
|
||||||
emailAddress string
|
EmailAddress string
|
||||||
call string
|
Call string
|
||||||
}
|
}
|
||||||
|
|
||||||
type labels struct {
|
type labels struct {
|
||||||
|
@ -55,13 +61,13 @@ type labelConfig struct {
|
||||||
Priority string
|
Priority string
|
||||||
Tags []string
|
Tags []string
|
||||||
Icon string
|
Icon string
|
||||||
emailAddress string
|
EmailAddress string
|
||||||
call string
|
Call string
|
||||||
}
|
}
|
||||||
|
|
||||||
type cacheConfig struct {
|
type cacheConfig struct {
|
||||||
// shared settings
|
// shared settings
|
||||||
Type cacheType
|
Type CacheType
|
||||||
Duration time.Duration
|
Duration time.Duration
|
||||||
// memory settings
|
// memory settings
|
||||||
CleanupInterval time.Duration
|
CleanupInterval time.Duration
|
||||||
|
@ -81,24 +87,25 @@ type resolvedConfig struct {
|
||||||
Icon string
|
Icon string
|
||||||
}
|
}
|
||||||
|
|
||||||
func readConfig(path string) (*config, error) {
|
// ReadConfig reads an scfg formatted file and returns the configuration struct.
|
||||||
|
func ReadConfig(path string) (*Config, error) {
|
||||||
cfg, err := scfg.Load(path)
|
cfg, err := scfg.Load(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
config := new(config)
|
config := new(Config)
|
||||||
// Set default values
|
// Set default values
|
||||||
config.HTTPAddress = "127.0.0.1:8080"
|
config.HTTPAddress = "127.0.0.1:8080"
|
||||||
config.LogLevel = "info"
|
config.LogLevel = "info"
|
||||||
config.alertMode = single
|
config.AlertMode = Single
|
||||||
|
|
||||||
config.cache.Type = memory
|
config.Cache.Type = Memory
|
||||||
config.cache.Duration = time.Hour * 24
|
config.Cache.Duration = time.Hour * 24
|
||||||
// memory
|
// memory
|
||||||
config.cache.CleanupInterval = time.Hour
|
config.Cache.CleanupInterval = time.Hour
|
||||||
// redis
|
// redis
|
||||||
config.cache.RedisURL = "redis://localhost:6379"
|
config.Cache.RedisURL = "redis://localhost:6379"
|
||||||
|
|
||||||
d := cfg.Get("log-level")
|
d := cfg.Get("log-level")
|
||||||
if d != nil {
|
if d != nil {
|
||||||
|
@ -130,10 +137,10 @@ func readConfig(path string) (*config, error) {
|
||||||
|
|
||||||
switch strings.ToLower(mode) {
|
switch strings.ToLower(mode) {
|
||||||
case "single":
|
case "single":
|
||||||
config.alertMode = single
|
config.AlertMode = Single
|
||||||
|
|
||||||
case "multi":
|
case "multi":
|
||||||
config.alertMode = multi
|
config.AlertMode = Multi
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("%q directive: illegal mode %q", d.Name, mode)
|
return nil, fmt.Errorf("%q directive: illegal mode %q", d.Name, mode)
|
||||||
|
@ -168,11 +175,11 @@ func readConfig(path string) (*config, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
config.labels.Order = strings.Split(order, ",")
|
config.Labels.Order = strings.Split(order, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
labels := make(map[string]labelConfig)
|
labels := make(map[string]labelConfig)
|
||||||
for _, labelName := range config.labels.Order {
|
for _, labelName := range config.Labels.Order {
|
||||||
for _, labelDir := range labelsDir.Children.GetAll(labelName) {
|
for _, labelDir := range labelsDir.Children.GetAll(labelName) {
|
||||||
labelConfig := new(labelConfig)
|
labelConfig := new(labelConfig)
|
||||||
var name string
|
var name string
|
||||||
|
@ -207,14 +214,14 @@ func readConfig(path string) (*config, error) {
|
||||||
|
|
||||||
d = labelDir.Children.Get("email-address")
|
d = labelDir.Children.Get("email-address")
|
||||||
if d != nil {
|
if d != nil {
|
||||||
if err := d.ParseParams(&labelConfig.emailAddress); err != nil {
|
if err := d.ParseParams(&labelConfig.EmailAddress); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d = labelDir.Children.Get("call")
|
d = labelDir.Children.Get("call")
|
||||||
if d != nil {
|
if d != nil {
|
||||||
if err := d.ParseParams(&labelConfig.call); err != nil {
|
if err := d.ParseParams(&labelConfig.Call); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,7 +230,7 @@ func readConfig(path string) (*config, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config.labels.Label = labels
|
config.Labels.Label = labels
|
||||||
}
|
}
|
||||||
|
|
||||||
ntfyDir := cfg.Get("ntfy")
|
ntfyDir := cfg.Get("ntfy")
|
||||||
|
@ -235,50 +242,50 @@ func readConfig(path string) (*config, error) {
|
||||||
if d == nil {
|
if d == nil {
|
||||||
return nil, fmt.Errorf("%q missing from %q directive", "topic", "ntfy")
|
return nil, fmt.Errorf("%q missing from %q directive", "topic", "ntfy")
|
||||||
}
|
}
|
||||||
if err := d.ParseParams(&config.ntfy.Topic); err != nil {
|
if err := d.ParseParams(&config.Ntfy.Topic); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
d = ntfyDir.Children.Get("user")
|
d = ntfyDir.Children.Get("user")
|
||||||
if d != nil {
|
if d != nil {
|
||||||
if err := d.ParseParams(&config.ntfy.User); err != nil {
|
if err := d.ParseParams(&config.Ntfy.User); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d = ntfyDir.Children.Get("password")
|
d = ntfyDir.Children.Get("password")
|
||||||
if d != nil {
|
if d != nil {
|
||||||
if err := d.ParseParams(&config.ntfy.Password); err != nil {
|
if err := d.ParseParams(&config.Ntfy.Password); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.ntfy.Password != "" && config.ntfy.User == "") ||
|
if (config.Ntfy.Password != "" && config.Ntfy.User == "") ||
|
||||||
(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")
|
return nil, errors.New("ntfy: user and password have to be set together")
|
||||||
}
|
}
|
||||||
|
|
||||||
d = ntfyDir.Children.Get("access-token")
|
d = ntfyDir.Children.Get("access-token")
|
||||||
if d != nil {
|
if d != nil {
|
||||||
if err := d.ParseParams(&config.ntfy.AccessToken); err != nil {
|
if err := d.ParseParams(&config.Ntfy.AccessToken); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.ntfy.User != "" && config.ntfy.AccessToken != "" {
|
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")
|
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")
|
d = ntfyDir.Children.Get("email-address")
|
||||||
if d != nil {
|
if d != nil {
|
||||||
if err := d.ParseParams(&config.ntfy.emailAddress); err != nil {
|
if err := d.ParseParams(&config.Ntfy.EmailAddress); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d = ntfyDir.Children.Get("call")
|
d = ntfyDir.Children.Get("call")
|
||||||
if d != nil {
|
if d != nil {
|
||||||
if err := d.ParseParams(&config.ntfy.call); err != nil {
|
if err := d.ParseParams(&config.Ntfy.Call); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -295,9 +302,9 @@ func readConfig(path string) (*config, error) {
|
||||||
|
|
||||||
switch strings.ToLower(cacheType) {
|
switch strings.ToLower(cacheType) {
|
||||||
case "memory":
|
case "memory":
|
||||||
config.cache.Type = memory
|
config.Cache.Type = Memory
|
||||||
case "redis":
|
case "redis":
|
||||||
config.cache.Type = redis
|
config.Cache.Type = Redis
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("cache: illegal type %q", cacheType)
|
return nil, fmt.Errorf("cache: illegal type %q", cacheType)
|
||||||
}
|
}
|
||||||
|
@ -315,7 +322,7 @@ func readConfig(path string) (*config, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
config.cache.Duration = duration
|
config.Cache.Duration = duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// memory
|
// memory
|
||||||
|
@ -331,13 +338,13 @@ func readConfig(path string) (*config, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
config.cache.CleanupInterval = interval
|
config.Cache.CleanupInterval = interval
|
||||||
}
|
}
|
||||||
|
|
||||||
// redis
|
// redis
|
||||||
d = cacheDir.Children.Get("redis-url")
|
d = cacheDir.Children.Get("redis-url")
|
||||||
if d != nil {
|
if d != nil {
|
||||||
if err := d.ParseParams(&config.cache.RedisURL); err != nil {
|
if err := d.ParseParams(&config.Cache.RedisURL); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,31 +365,31 @@ func readConfig(path string) (*config, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
config.am.SilenceDuration = duration
|
config.Am.SilenceDuration = duration
|
||||||
}
|
}
|
||||||
|
|
||||||
d = amDir.Children.Get("user")
|
d = amDir.Children.Get("user")
|
||||||
if d != nil {
|
if d != nil {
|
||||||
if err := d.ParseParams(&config.am.User); err != nil {
|
if err := d.ParseParams(&config.Am.User); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d = amDir.Children.Get("password")
|
d = amDir.Children.Get("password")
|
||||||
if d != nil {
|
if d != nil {
|
||||||
if err := d.ParseParams(&config.am.Password); err != nil {
|
if err := d.ParseParams(&config.Am.Password); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.am.Password != "" && config.am.User == "") ||
|
if (config.Am.Password != "" && config.Am.User == "") ||
|
||||||
(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 nil, errors.New("alertmanager: user and password have to be set together")
|
||||||
}
|
}
|
||||||
|
|
||||||
d = amDir.Children.Get("url")
|
d = amDir.Children.Get("url")
|
||||||
if d != nil {
|
if d != nil {
|
||||||
if err := d.ParseParams(&config.am.URL); err != nil {
|
if err := d.ParseParams(&config.Am.URL); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -397,12 +404,12 @@ func readConfig(path string) (*config, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
config.resolved.Tags = strings.Split(tags, ",")
|
config.Resolved.Tags = strings.Split(tags, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
d = resolvedDir.Children.Get("icon")
|
d = resolvedDir.Children.Get("icon")
|
||||||
if d != nil {
|
if d != nil {
|
||||||
if err := d.ParseParams(&config.resolved.Icon); err != nil {
|
if err := d.ParseParams(&config.Resolved.Icon); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
@ -62,40 +62,40 @@ cache {
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
expectedCfg := &config{
|
expectedCfg := &Config{
|
||||||
BaseURL: "https://ntfy-alertmanager.xenrox.net",
|
BaseURL: "https://ntfy-alertmanager.xenrox.net",
|
||||||
HTTPAddress: ":8080",
|
HTTPAddress: ":8080",
|
||||||
LogLevel: "info",
|
LogLevel: "info",
|
||||||
alertMode: multi,
|
AlertMode: Multi,
|
||||||
User: "webhookUser",
|
User: "webhookUser",
|
||||||
Password: "webhookPass",
|
Password: "webhookPass",
|
||||||
ntfy: ntfyConfig{Topic: "https://ntfy.sh/alertmanager-alerts", User: "user", Password: "pass"},
|
Ntfy: ntfyConfig{Topic: "https://ntfy.sh/alertmanager-alerts", User: "user", Password: "pass"},
|
||||||
labels: labels{Order: []string{"severity", "instance"},
|
Labels: labels{Order: []string{"severity", "instance"},
|
||||||
Label: map[string]labelConfig{
|
Label: map[string]labelConfig{
|
||||||
"severity:critical": {
|
"severity:critical": {
|
||||||
Priority: "5",
|
Priority: "5",
|
||||||
Tags: []string{"rotating_light"},
|
Tags: []string{"rotating_light"},
|
||||||
Icon: "https://foo.com/critical.png",
|
Icon: "https://foo.com/critical.png",
|
||||||
emailAddress: "foo@bar.com",
|
EmailAddress: "foo@bar.com",
|
||||||
call: "yes",
|
Call: "yes",
|
||||||
},
|
},
|
||||||
"severity:info": {Priority: "1"},
|
"severity:info": {Priority: "1"},
|
||||||
"instance:example.com": {Tags: []string{"computer", "example"}},
|
"instance:example.com": {Tags: []string{"computer", "example"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
cache: cacheConfig{
|
Cache: cacheConfig{
|
||||||
Type: redis,
|
Type: Redis,
|
||||||
Duration: 48 * time.Hour,
|
Duration: 48 * time.Hour,
|
||||||
CleanupInterval: time.Hour,
|
CleanupInterval: time.Hour,
|
||||||
RedisURL: "redis://user:password@localhost:6789/3",
|
RedisURL: "redis://user:password@localhost:6789/3",
|
||||||
},
|
},
|
||||||
am: alertmanagerConfig{
|
Am: alertmanagerConfig{
|
||||||
SilenceDuration: time.Hour * 24,
|
SilenceDuration: time.Hour * 24,
|
||||||
User: "user",
|
User: "user",
|
||||||
Password: "pass",
|
Password: "pass",
|
||||||
URL: "https://alertmanager.xenrox.net",
|
URL: "https://alertmanager.xenrox.net",
|
||||||
},
|
},
|
||||||
resolved: resolvedConfig{
|
Resolved: resolvedConfig{
|
||||||
Tags: []string{"resolved", "partying_face"},
|
Tags: []string{"resolved", "partying_face"},
|
||||||
Icon: "https://foo.com/resolved.png",
|
Icon: "https://foo.com/resolved.png",
|
||||||
},
|
},
|
||||||
|
@ -107,7 +107,7 @@ cache {
|
||||||
t.Errorf("failed to write config file: %v", err)
|
t.Errorf("failed to write config file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := readConfig(configPath)
|
cfg, err := ReadConfig(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to read config file: %v", err)
|
t.Errorf("failed to read config file: %v", err)
|
||||||
}
|
}
|
67
main.go
67
main.go
|
@ -16,6 +16,7 @@ import (
|
||||||
|
|
||||||
"git.xenrox.net/~xenrox/go-log"
|
"git.xenrox.net/~xenrox/go-log"
|
||||||
"git.xenrox.net/~xenrox/ntfy-alertmanager/cache"
|
"git.xenrox.net/~xenrox/ntfy-alertmanager/cache"
|
||||||
|
"git.xenrox.net/~xenrox/ntfy-alertmanager/config"
|
||||||
"golang.org/x/text/cases"
|
"golang.org/x/text/cases"
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
)
|
)
|
||||||
|
@ -23,7 +24,7 @@ import (
|
||||||
var version = "dev"
|
var version = "dev"
|
||||||
|
|
||||||
type bridge struct {
|
type bridge struct {
|
||||||
cfg *config
|
cfg *config.Config
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
cache cache.Cache
|
cache cache.Cache
|
||||||
client *httpClient
|
client *httpClient
|
||||||
|
@ -102,20 +103,20 @@ func (br *bridge) singleAlertNotifications(p *payload) []*notification {
|
||||||
|
|
||||||
var tags []string
|
var tags []string
|
||||||
if alert.Status == "resolved" {
|
if alert.Status == "resolved" {
|
||||||
tags = append(tags, br.cfg.resolved.Tags...)
|
tags = append(tags, br.cfg.Resolved.Tags...)
|
||||||
n.icon = br.cfg.resolved.Icon
|
n.icon = br.cfg.Resolved.Icon
|
||||||
}
|
}
|
||||||
|
|
||||||
n.emailAddress = br.cfg.ntfy.emailAddress
|
n.emailAddress = br.cfg.Ntfy.EmailAddress
|
||||||
n.call = br.cfg.ntfy.call
|
n.call = br.cfg.Ntfy.Call
|
||||||
|
|
||||||
for _, labelName := range br.cfg.labels.Order {
|
for _, labelName := range br.cfg.Labels.Order {
|
||||||
val, ok := alert.Labels[labelName]
|
val, ok := alert.Labels[labelName]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
labelConfig, ok := br.cfg.labels.Label[fmt.Sprintf("%s:%s", labelName, val)]
|
labelConfig, ok := br.cfg.Labels.Label[fmt.Sprintf("%s:%s", labelName, val)]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -129,11 +130,11 @@ func (br *bridge) singleAlertNotifications(p *payload) []*notification {
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.emailAddress == "" {
|
if n.emailAddress == "" {
|
||||||
n.emailAddress = labelConfig.emailAddress
|
n.emailAddress = labelConfig.EmailAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.call == "" {
|
if n.call == "" {
|
||||||
n.call = labelConfig.call
|
n.call = labelConfig.Call
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, val := range labelConfig.Tags {
|
for _, val := range labelConfig.Tags {
|
||||||
|
@ -145,7 +146,7 @@ func (br *bridge) singleAlertNotifications(p *payload) []*notification {
|
||||||
|
|
||||||
n.tags = strings.Join(tags, ",")
|
n.tags = strings.Join(tags, ",")
|
||||||
|
|
||||||
if br.cfg.am.SilenceDuration != 0 && alert.Status == "firing" {
|
if br.cfg.Am.SilenceDuration != 0 && alert.Status == "firing" {
|
||||||
if br.cfg.BaseURL == "" {
|
if br.cfg.BaseURL == "" {
|
||||||
br.logger.Error("Failed to create silence action: No base-url set")
|
br.logger.Error("Failed to create silence action: No base-url set")
|
||||||
} else {
|
} else {
|
||||||
|
@ -210,20 +211,20 @@ func (br *bridge) multiAlertNotification(p *payload) *notification {
|
||||||
|
|
||||||
var tags []string
|
var tags []string
|
||||||
if p.Status == "resolved" {
|
if p.Status == "resolved" {
|
||||||
tags = append(tags, br.cfg.resolved.Tags...)
|
tags = append(tags, br.cfg.Resolved.Tags...)
|
||||||
n.icon = br.cfg.resolved.Icon
|
n.icon = br.cfg.Resolved.Icon
|
||||||
}
|
}
|
||||||
|
|
||||||
n.emailAddress = br.cfg.ntfy.emailAddress
|
n.emailAddress = br.cfg.Ntfy.EmailAddress
|
||||||
n.call = br.cfg.ntfy.call
|
n.call = br.cfg.Ntfy.Call
|
||||||
|
|
||||||
for _, labelName := range br.cfg.labels.Order {
|
for _, labelName := range br.cfg.Labels.Order {
|
||||||
val, ok := p.CommonLabels[labelName]
|
val, ok := p.CommonLabels[labelName]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
labelConfig, ok := br.cfg.labels.Label[fmt.Sprintf("%s:%s", labelName, val)]
|
labelConfig, ok := br.cfg.Labels.Label[fmt.Sprintf("%s:%s", labelName, val)]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -237,11 +238,11 @@ func (br *bridge) multiAlertNotification(p *payload) *notification {
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.emailAddress == "" {
|
if n.emailAddress == "" {
|
||||||
n.emailAddress = labelConfig.emailAddress
|
n.emailAddress = labelConfig.EmailAddress
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.call == "" {
|
if n.call == "" {
|
||||||
n.call = labelConfig.call
|
n.call = labelConfig.Call
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, val := range labelConfig.Tags {
|
for _, val := range labelConfig.Tags {
|
||||||
|
@ -253,7 +254,7 @@ func (br *bridge) multiAlertNotification(p *payload) *notification {
|
||||||
|
|
||||||
n.tags = strings.Join(tags, ",")
|
n.tags = strings.Join(tags, ",")
|
||||||
|
|
||||||
if br.cfg.am.SilenceDuration != 0 && p.Status == "firing" {
|
if br.cfg.Am.SilenceDuration != 0 && p.Status == "firing" {
|
||||||
if br.cfg.BaseURL == "" {
|
if br.cfg.BaseURL == "" {
|
||||||
br.logger.Error("Failed to create silence action: No base-url set")
|
br.logger.Error("Failed to create silence action: No base-url set")
|
||||||
} else {
|
} else {
|
||||||
|
@ -272,16 +273,16 @@ func (br *bridge) multiAlertNotification(p *payload) *notification {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (br *bridge) publish(n *notification) error {
|
func (br *bridge) publish(n *notification) error {
|
||||||
req, err := http.NewRequest(http.MethodPost, br.cfg.ntfy.Topic, strings.NewReader(n.body))
|
req, err := http.NewRequest(http.MethodPost, br.cfg.Ntfy.Topic, strings.NewReader(n.body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ntfy authentication
|
// ntfy authentication
|
||||||
if br.cfg.ntfy.Password != "" && br.cfg.ntfy.User != "" {
|
if br.cfg.Ntfy.Password != "" && br.cfg.Ntfy.User != "" {
|
||||||
req.SetBasicAuth(br.cfg.ntfy.User, br.cfg.ntfy.Password)
|
req.SetBasicAuth(br.cfg.Ntfy.User, br.cfg.Ntfy.Password)
|
||||||
} else if br.cfg.ntfy.AccessToken != "" {
|
} else if br.cfg.Ntfy.AccessToken != "" {
|
||||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", br.cfg.ntfy.AccessToken))
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", br.cfg.Ntfy.AccessToken))
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("X-Title", n.title)
|
req.Header.Set("X-Title", n.title)
|
||||||
|
@ -363,7 +364,7 @@ func (br *bridge) handleWebhooks(w http.ResponseWriter, r *http.Request) {
|
||||||
br.logger.Debugf("Received alert %+v", event)
|
br.logger.Debugf("Received alert %+v", event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if br.cfg.alertMode == single {
|
if br.cfg.AlertMode == config.Single {
|
||||||
notifications := br.singleAlertNotifications(&event)
|
notifications := br.singleAlertNotifications(&event)
|
||||||
for _, n := range notifications {
|
for _, n := range notifications {
|
||||||
err := br.publish(n)
|
err := br.publish(n)
|
||||||
|
@ -412,7 +413,7 @@ func (br *bridge) basicAuthMiddleware(handler http.HandlerFunc) http.HandlerFunc
|
||||||
|
|
||||||
func (br *bridge) runCleanup() {
|
func (br *bridge) runCleanup() {
|
||||||
for {
|
for {
|
||||||
time.Sleep(br.cfg.cache.CleanupInterval)
|
time.Sleep(br.cfg.Cache.CleanupInterval)
|
||||||
br.logger.Info("Pruning cache")
|
br.logger.Info("Pruning cache")
|
||||||
br.cache.Cleanup()
|
br.cache.Cleanup()
|
||||||
}
|
}
|
||||||
|
@ -432,7 +433,7 @@ func main() {
|
||||||
|
|
||||||
logger := log.NewDefaultLogger()
|
logger := log.NewDefaultLogger()
|
||||||
|
|
||||||
cfg, err := readConfig(configPath)
|
cfg, err := config.ReadConfig(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatalf("Failed to read config: %v", err)
|
logger.Fatalf("Failed to read config: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -444,12 +445,12 @@ func main() {
|
||||||
client := &httpClient{&http.Client{Timeout: time.Second * 3}}
|
client := &httpClient{&http.Client{Timeout: time.Second * 3}}
|
||||||
|
|
||||||
var c cache.Cache
|
var c cache.Cache
|
||||||
switch cfg.cache.Type {
|
switch cfg.Cache.Type {
|
||||||
case memory:
|
case config.Memory:
|
||||||
c = cache.NewMemoryCache(cfg.cache.Duration)
|
c = cache.NewMemoryCache(cfg.Cache.Duration)
|
||||||
case redis:
|
case config.Redis:
|
||||||
var err error
|
var err error
|
||||||
c, err = cache.NewRedisCache(cfg.cache.RedisURL, cfg.cache.Duration)
|
c, err = cache.NewRedisCache(cfg.Cache.RedisURL, cfg.Cache.Duration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatalf("Failed to create redis cache: %v", err)
|
logger.Fatalf("Failed to create redis cache: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -467,7 +468,7 @@ func main() {
|
||||||
http.HandleFunc("/silences", bridge.handleSilences)
|
http.HandleFunc("/silences", bridge.handleSilences)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.cache.Type == memory {
|
if cfg.Cache.Type == config.Memory {
|
||||||
go bridge.runCleanup()
|
go bridge.runCleanup()
|
||||||
}
|
}
|
||||||
logger.Fatal(http.ListenAndServe(cfg.HTTPAddress, nil))
|
logger.Fatal(http.ListenAndServe(cfg.HTTPAddress, nil))
|
||||||
|
|
10
silence.go
10
silence.go
|
@ -77,7 +77,7 @@ func (br *bridge) handleSilences(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
silence := &silence{
|
silence := &silence{
|
||||||
StartsAt: time.Now().UTC().Format(dateLayout),
|
StartsAt: time.Now().UTC().Format(dateLayout),
|
||||||
EndsAt: time.Now().Add(br.cfg.am.SilenceDuration).UTC().Format(dateLayout),
|
EndsAt: time.Now().Add(br.cfg.Am.SilenceDuration).UTC().Format(dateLayout),
|
||||||
CreatedBy: "ntfy-alertmanager",
|
CreatedBy: "ntfy-alertmanager",
|
||||||
Comment: "",
|
Comment: "",
|
||||||
Matchers: matchers,
|
Matchers: matchers,
|
||||||
|
@ -90,8 +90,8 @@ func (br *bridge) handleSilences(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
url := sb.AlertManagerURL
|
url := sb.AlertManagerURL
|
||||||
if br.cfg.am.URL != "" {
|
if br.cfg.Am.URL != "" {
|
||||||
url = br.cfg.am.URL
|
url = br.cfg.Am.URL
|
||||||
}
|
}
|
||||||
url += "/api/v2/silences"
|
url += "/api/v2/silences"
|
||||||
|
|
||||||
|
@ -102,8 +102,8 @@ func (br *bridge) handleSilences(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basic auth
|
// Basic auth
|
||||||
if br.cfg.am.User != "" && br.cfg.am.Password != "" {
|
if br.cfg.Am.User != "" && br.cfg.Am.Password != "" {
|
||||||
req.SetBasicAuth(br.cfg.am.User, br.cfg.am.Password)
|
req.SetBasicAuth(br.cfg.Am.User, br.cfg.Am.Password)
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
|
Loading…
Reference in a new issue