Add ntfy email support
Implements: https://todo.xenrox.net/~xenrox/ntfy-alertmanager/15
This commit is contained in:
parent
3bdecb70da
commit
025ad78a60
4 changed files with 63 additions and 19 deletions
11
README.md
11
README.md
|
@ -16,9 +16,9 @@ You can specify the configuration file location with the `--config` flag. By def
|
||||||
the configuration file will be read from `/etc/ntfy-alertmanager/config`. The format
|
the configuration file will be read from `/etc/ntfy-alertmanager/config`. The format
|
||||||
of this file is [scfg].
|
of this file is [scfg].
|
||||||
|
|
||||||
ntfy-alertmanager has support for setting ntfy [priority], [tags], [icon] and [action buttons]
|
ntfy-alertmanager has support for setting ntfy [priority], [tags], [icon], [action buttons]
|
||||||
(which can be used to create an Alertmanager silence).
|
(which can be used to create an Alertmanager silence) and [email notifications].
|
||||||
Define a decreasing order of labels in the config file and map those labels to tags, priority or an icon.
|
Define a decreasing order of labels in the config file and map those labels to tags, priority, an icon or an email address.
|
||||||
|
|
||||||
- For priority and icon the first found value will be chosen. An icon for "resolved" alerts will take precedence.
|
- For priority and icon the first found value will be chosen. An icon for "resolved" alerts will take precedence.
|
||||||
- Tags are added together.
|
- Tags are added together.
|
||||||
|
@ -47,6 +47,8 @@ labels {
|
||||||
priority 5
|
priority 5
|
||||||
tags "rotating_light"
|
tags "rotating_light"
|
||||||
icon "https://foo.com/critical.png"
|
icon "https://foo.com/critical.png"
|
||||||
|
# Forward messages which severity "critical" to the specified email address.
|
||||||
|
email-address foo@bar.com
|
||||||
}
|
}
|
||||||
|
|
||||||
severity "info" {
|
severity "info" {
|
||||||
|
@ -73,6 +75,8 @@ ntfy {
|
||||||
# ntfy authentication via access tokens (https://docs.ntfy.sh/publish/#access-tokens)
|
# ntfy authentication via access tokens (https://docs.ntfy.sh/publish/#access-tokens)
|
||||||
# Either access-token or a user/password combination can be used - not both.
|
# Either access-token or a user/password combination can be used - not both.
|
||||||
access-token foobar
|
access-token foobar
|
||||||
|
# Forward all messages to the specified email address.
|
||||||
|
email-address foo@bar.com
|
||||||
}
|
}
|
||||||
|
|
||||||
alertmanager {
|
alertmanager {
|
||||||
|
@ -135,6 +139,7 @@ or write to me directly on matrix [@xenrox:xenrox.net].
|
||||||
[tags]: https://ntfy.sh/docs/publish/#tags-emojis
|
[tags]: https://ntfy.sh/docs/publish/#tags-emojis
|
||||||
[icon]: https://docs.ntfy.sh/publish/#icons
|
[icon]: https://docs.ntfy.sh/publish/#icons
|
||||||
[action buttons]: https://docs.ntfy.sh/publish/#action-buttons
|
[action buttons]: https://docs.ntfy.sh/publish/#action-buttons
|
||||||
|
[email notifications]: https://docs.ntfy.sh/publish/#e-mail-notifications
|
||||||
[issue tracker]: https://todo.xenrox.net/~xenrox/ntfy-alertmanager
|
[issue tracker]: https://todo.xenrox.net/~xenrox/ntfy-alertmanager
|
||||||
[mailing list]: https://lists.xenrox.net/~xenrox/public-inbox
|
[mailing list]: https://lists.xenrox.net/~xenrox/public-inbox
|
||||||
[@xenrox:xenrox.net]: https://matrix.to/#/@xenrox:xenrox.net
|
[@xenrox:xenrox.net]: https://matrix.to/#/@xenrox:xenrox.net
|
||||||
|
|
30
config.go
30
config.go
|
@ -38,10 +38,11 @@ type config struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ntfyConfig struct {
|
type ntfyConfig struct {
|
||||||
Topic string
|
Topic string
|
||||||
User string
|
User string
|
||||||
Password string
|
Password string
|
||||||
AccessToken string
|
AccessToken string
|
||||||
|
emailAddress string
|
||||||
}
|
}
|
||||||
|
|
||||||
type labels struct {
|
type labels struct {
|
||||||
|
@ -50,9 +51,10 @@ type labels struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type labelConfig struct {
|
type labelConfig struct {
|
||||||
Priority string
|
Priority string
|
||||||
Tags []string
|
Tags []string
|
||||||
Icon string
|
Icon string
|
||||||
|
emailAddress string
|
||||||
}
|
}
|
||||||
|
|
||||||
type cacheConfig struct {
|
type cacheConfig struct {
|
||||||
|
@ -201,6 +203,13 @@ func readConfig(path string) (*config, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d = labelDir.Children.Get("email-address")
|
||||||
|
if d != nil {
|
||||||
|
if err := d.ParseParams(&labelConfig.emailAddress); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
labels[fmt.Sprintf("%s:%s", labelName, name)] = *labelConfig
|
labels[fmt.Sprintf("%s:%s", labelName, name)] = *labelConfig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,6 +260,13 @@ func readConfig(path string) (*config, error) {
|
||||||
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")
|
||||||
|
if d != nil {
|
||||||
|
if err := d.ParseParams(&config.ntfy.emailAddress); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cacheDir := cfg.Get("cache")
|
cacheDir := cfg.Get("cache")
|
||||||
|
|
||||||
if cacheDir != nil {
|
if cacheDir != nil {
|
||||||
|
|
|
@ -24,6 +24,7 @@ labels {
|
||||||
priority 5
|
priority 5
|
||||||
tags "rotating_light"
|
tags "rotating_light"
|
||||||
icon "https://foo.com/critical.png"
|
icon "https://foo.com/critical.png"
|
||||||
|
email-address foo@bar.com
|
||||||
}
|
}
|
||||||
|
|
||||||
severity "info" {
|
severity "info" {
|
||||||
|
@ -70,7 +71,12 @@ cache {
|
||||||
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": {Priority: "5", Tags: []string{"rotating_light"}, Icon: "https://foo.com/critical.png"},
|
"severity:critical": {
|
||||||
|
Priority: "5",
|
||||||
|
Tags: []string{"rotating_light"},
|
||||||
|
Icon: "https://foo.com/critical.png",
|
||||||
|
emailAddress: "foo@bar.com",
|
||||||
|
},
|
||||||
"severity:info": {Priority: "1"},
|
"severity:info": {Priority: "1"},
|
||||||
"instance:example.com": {Tags: []string{"computer", "example"}},
|
"instance:example.com": {Tags: []string{"computer", "example"}},
|
||||||
},
|
},
|
||||||
|
|
33
main.go
33
main.go
|
@ -46,14 +46,15 @@ type alert struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type notification struct {
|
type notification struct {
|
||||||
title string
|
title string
|
||||||
body string
|
body string
|
||||||
priority string
|
priority string
|
||||||
tags string
|
tags string
|
||||||
icon string
|
icon string
|
||||||
silenceBody string
|
emailAddress string
|
||||||
fingerprint string
|
silenceBody string
|
||||||
status string
|
fingerprint string
|
||||||
|
status string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (br *bridge) singleAlertNotifications(p *payload) []*notification {
|
func (br *bridge) singleAlertNotifications(p *payload) []*notification {
|
||||||
|
@ -100,6 +101,8 @@ func (br *bridge) singleAlertNotifications(p *payload) []*notification {
|
||||||
n.icon = br.cfg.resolved.Icon
|
n.icon = br.cfg.resolved.Icon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n.emailAddress = br.cfg.ntfy.emailAddress
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -119,6 +122,10 @@ func (br *bridge) singleAlertNotifications(p *payload) []*notification {
|
||||||
n.icon = labelConfig.Icon
|
n.icon = labelConfig.Icon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if n.emailAddress == "" {
|
||||||
|
n.emailAddress = labelConfig.emailAddress
|
||||||
|
}
|
||||||
|
|
||||||
for _, val := range labelConfig.Tags {
|
for _, val := range labelConfig.Tags {
|
||||||
if !sliceContains(tags, val) {
|
if !sliceContains(tags, val) {
|
||||||
tags = append(tags, val)
|
tags = append(tags, val)
|
||||||
|
@ -197,6 +204,8 @@ func (br *bridge) multiAlertNotification(p *payload) *notification {
|
||||||
n.icon = br.cfg.resolved.Icon
|
n.icon = br.cfg.resolved.Icon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n.emailAddress = br.cfg.ntfy.emailAddress
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -216,6 +225,10 @@ func (br *bridge) multiAlertNotification(p *payload) *notification {
|
||||||
n.icon = labelConfig.Icon
|
n.icon = labelConfig.Icon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if n.emailAddress == "" {
|
||||||
|
n.emailAddress = labelConfig.emailAddress
|
||||||
|
}
|
||||||
|
|
||||||
for _, val := range labelConfig.Tags {
|
for _, val := range labelConfig.Tags {
|
||||||
if !sliceContains(tags, val) {
|
if !sliceContains(tags, val) {
|
||||||
tags = append(tags, val)
|
tags = append(tags, val)
|
||||||
|
@ -270,6 +283,10 @@ func (br *bridge) publish(n *notification) error {
|
||||||
req.Header.Set("X-Tags", n.tags)
|
req.Header.Set("X-Tags", n.tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if n.emailAddress != "" {
|
||||||
|
req.Header.Set("X-Email", n.emailAddress)
|
||||||
|
}
|
||||||
|
|
||||||
if n.silenceBody != "" {
|
if n.silenceBody != "" {
|
||||||
url := br.cfg.BaseURL + "/silences"
|
url := br.cfg.BaseURL + "/silences"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue