support loading pushover secrets from files (#3200)

* support loading pushover secrets from files

Add the user_key_file and token_file keys to the pushover config.

/cc https://github.com/prometheus/alertmanager/issues/2498

Signed-off-by: Simon Rozet <me@simonrozet.com>
This commit is contained in:
Simon Rozet 2023-01-18 23:33:42 +01:00 committed by GitHub
parent 9c7adc4024
commit a8e4c166a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 20 deletions

View File

@ -667,7 +667,9 @@ type PushoverConfig struct {
HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`
UserKey Secret `yaml:"user_key,omitempty" json:"user_key,omitempty"`
UserKeyFile string `yaml:"user_key_file,omitempty" json:"user_key_file,omitempty"`
Token Secret `yaml:"token,omitempty" json:"token,omitempty"`
TokenFile string `yaml:"token_file,omitempty" json:"token_file,omitempty"`
Title string `yaml:"title,omitempty" json:"title,omitempty"`
Message string `yaml:"message,omitempty" json:"message,omitempty"`
URL string `yaml:"url,omitempty" json:"url,omitempty"`
@ -686,11 +688,17 @@ func (c *PushoverConfig) UnmarshalYAML(unmarshal func(interface{}) error) error
if err := unmarshal((*plain)(c)); err != nil {
return err
}
if c.UserKey == "" {
return fmt.Errorf("missing user key in Pushover config")
if c.UserKey == "" && c.UserKeyFile == "" {
return fmt.Errorf("one of user_key or user_key_file must be configured")
}
if c.Token == "" {
return fmt.Errorf("missing token in Pushover config")
if c.UserKey != "" && c.UserKeyFile != "" {
return fmt.Errorf("at most one of user_key & user_key_file must be configured")
}
if c.Token == "" && c.TokenFile == "" {
return fmt.Errorf("one of token or token_file must be configured")
}
if c.Token != "" && c.TokenFile != "" {
return fmt.Errorf("at most one of token & token_file must be configured")
}
return nil
}

View File

@ -391,7 +391,25 @@ user_key: ''
var cfg PushoverConfig
err := yaml.UnmarshalStrict([]byte(in), &cfg)
expected := "missing user key in Pushover config"
expected := "one of user_key or user_key_file must be configured"
if err == nil {
t.Fatalf("no error returned, expected:\n%v", expected)
}
if err.Error() != expected {
t.Errorf("\nexpected:\n%v\ngot:\n%v", expected, err.Error())
}
}
func TestPushoverUserKeyOrUserKeyFile(t *testing.T) {
in := `
user_key: 'user key'
user_key_file: /pushover/user_key
`
var cfg PushoverConfig
err := yaml.UnmarshalStrict([]byte(in), &cfg)
expected := "at most one of user_key & user_key_file must be configured"
if err == nil {
t.Fatalf("no error returned, expected:\n%v", expected)
@ -409,7 +427,26 @@ token: ''
var cfg PushoverConfig
err := yaml.UnmarshalStrict([]byte(in), &cfg)
expected := "missing token in Pushover config"
expected := "one of token or token_file must be configured"
if err == nil {
t.Fatalf("no error returned, expected:\n%v", expected)
}
if err.Error() != expected {
t.Errorf("\nexpected:\n%v\ngot:\n%v", expected, err.Error())
}
}
func TestPushoverTokenOrTokenFile(t *testing.T) {
in := `
token: 'pushover token'
token_file: /pushover/token
user_key: 'user key'
`
var cfg PushoverConfig
err := yaml.UnmarshalStrict([]byte(in), &cfg)
expected := "at most one of token & token_file must be configured"
if err == nil {
t.Fatalf("no error returned, expected:\n%v", expected)

View File

@ -862,13 +862,17 @@ Pushover notifications are sent via the [Pushover API](https://pushover.net/api)
# Whether to notify about resolved alerts.
[ send_resolved: <boolean> | default = true ]
# The recipient user's user key.
# The recipient user's key.
# user_key and user_key_file are mutually exclusive.
user_key: <secret>
user_key_file: <filepath>
# Your registered application's API token, see https://pushover.net/apps
# You can also register a token by cloning this Prometheus app:
# https://pushover.net/apps/clone/prometheus
# token and token_file are mutually exclusive.
token: <secret>
token_file: <filepath>
# Notification title.
[ title: <tmpl_string> | default = '{{ template "pushover.default.title" . }}' ]

View File

@ -18,6 +18,7 @@ import (
"fmt"
"net/http"
"net/url"
"os"
"strings"
"time"
@ -83,9 +84,32 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
tmpl := notify.TmplText(n.tmpl, data, &err)
tmplHTML := notify.TmplHTML(n.tmpl, data, &err)
var (
token string
userKey string
)
if n.conf.Token != "" {
token = string(n.conf.Token)
} else {
content, err := os.ReadFile(n.conf.TokenFile)
if err != nil {
return false, fmt.Errorf("read token_file: %w", err)
}
token = string(content)
}
if n.conf.UserKey != "" {
userKey = string(n.conf.UserKey)
} else {
content, err := os.ReadFile(n.conf.UserKeyFile)
if err != nil {
return false, fmt.Errorf("read user_key_file: %w", err)
}
userKey = string(content)
}
parameters := url.Values{}
parameters.Add("token", tmpl(string(n.conf.Token)))
parameters.Add("user", tmpl(string(n.conf.UserKey)))
parameters.Add("token", tmpl(token))
parameters.Add("user", tmpl(userKey))
title, truncated := notify.TruncateInRunes(tmpl(n.conf.Title), maxTitleLenRunes)
if truncated {