Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions config/notifiers.go
Original file line number Diff line number Diff line change
Expand Up @@ -666,17 +666,19 @@ type PushoverConfig struct {

HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`

UserKey Secret `yaml:"user_key,omitempty" json:"user_key,omitempty"`
Token Secret `yaml:"token,omitempty" json:"token,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"`
URLTitle string `yaml:"url_title,omitempty" json:"url_title,omitempty"`
Sound string `yaml:"sound,omitempty" json:"sound,omitempty"`
Priority string `yaml:"priority,omitempty" json:"priority,omitempty"`
Retry duration `yaml:"retry,omitempty" json:"retry,omitempty"`
Expire duration `yaml:"expire,omitempty" json:"expire,omitempty"`
HTML bool `yaml:"html" json:"html,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"`
URLTitle string `yaml:"url_title,omitempty" json:"url_title,omitempty"`
Sound string `yaml:"sound,omitempty" json:"sound,omitempty"`
Priority string `yaml:"priority,omitempty" json:"priority,omitempty"`
Retry duration `yaml:"retry,omitempty" json:"retry,omitempty"`
Expire duration `yaml:"expire,omitempty" json:"expire,omitempty"`
HTML bool `yaml:"html" json:"html,omitempty"`
}

// UnmarshalYAML implements the yaml.Unmarshaler interface.
Expand All @@ -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
}
Expand Down
41 changes: 39 additions & 2 deletions config/notifiers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
6 changes: 5 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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" . }}' ]
Expand Down
28 changes: 26 additions & 2 deletions notify/pushover/pushover.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"fmt"
"net/http"
"net/url"
"os"
"strings"
"time"

Expand Down Expand Up @@ -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 {
Expand Down