Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(discord): add global and secret file for discord notifier #3308

Closed
wants to merge 1 commit into from
Closed
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
feat(discord): add global and secret file for discord notifier
Signed-off-by: budimanjojo <budimanjojo@gmail.com>
  • Loading branch information
budimanjojo committed Apr 7, 2023
commit f0f3167b914a2af0727c8c1b372517eeea68c1dd
60 changes: 35 additions & 25 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,10 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
return fmt.Errorf("at most one of smtp_auth_password & smtp_auth_password_file must be configured")
}

if c.Global.DiscordWebhookURL != nil && len(c.Global.DiscordWebhookURLFile) > 0 {
return fmt.Errorf("at most one of discord_webhook_url & discord_webhook_url_file must be configured")
}

names := map[string]struct{}{}

for _, rcv := range c.Receivers {
Expand Down Expand Up @@ -512,8 +516,12 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
if discord.HTTPConfig == nil {
discord.HTTPConfig = c.Global.HTTPConfig
}
if discord.WebhookURL == nil {
return fmt.Errorf("no discord webhook URL provided")
if discord.WebhookURL == nil && len(discord.WebhookURLFile) == 0 {
if c.Global.DiscordWebhookURL == nil && len(c.Global.DiscordWebhookURLFile) == 0 {
return fmt.Errorf("no global Discord webhook URL set")
}
discord.WebhookURL = c.Global.DiscordWebhookURL
discord.WebhookURLFile = c.Global.DiscordWebhookURLFile
}
}
for _, webex := range rcv.WebexConfigs {
Expand Down Expand Up @@ -730,29 +738,31 @@ type GlobalConfig struct {

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

SMTPFrom string `yaml:"smtp_from,omitempty" json:"smtp_from,omitempty"`
SMTPHello string `yaml:"smtp_hello,omitempty" json:"smtp_hello,omitempty"`
SMTPSmarthost HostPort `yaml:"smtp_smarthost,omitempty" json:"smtp_smarthost,omitempty"`
SMTPAuthUsername string `yaml:"smtp_auth_username,omitempty" json:"smtp_auth_username,omitempty"`
SMTPAuthPassword Secret `yaml:"smtp_auth_password,omitempty" json:"smtp_auth_password,omitempty"`
SMTPAuthPasswordFile string `yaml:"smtp_auth_password_file,omitempty" json:"smtp_auth_password_file,omitempty"`
SMTPAuthSecret Secret `yaml:"smtp_auth_secret,omitempty" json:"smtp_auth_secret,omitempty"`
SMTPAuthIdentity string `yaml:"smtp_auth_identity,omitempty" json:"smtp_auth_identity,omitempty"`
SMTPRequireTLS bool `yaml:"smtp_require_tls" json:"smtp_require_tls,omitempty"`
SlackAPIURL *SecretURL `yaml:"slack_api_url,omitempty" json:"slack_api_url,omitempty"`
SlackAPIURLFile string `yaml:"slack_api_url_file,omitempty" json:"slack_api_url_file,omitempty"`
PagerdutyURL *URL `yaml:"pagerduty_url,omitempty" json:"pagerduty_url,omitempty"`
OpsGenieAPIURL *URL `yaml:"opsgenie_api_url,omitempty" json:"opsgenie_api_url,omitempty"`
OpsGenieAPIKey Secret `yaml:"opsgenie_api_key,omitempty" json:"opsgenie_api_key,omitempty"`
OpsGenieAPIKeyFile string `yaml:"opsgenie_api_key_file,omitempty" json:"opsgenie_api_key_file,omitempty"`
WeChatAPIURL *URL `yaml:"wechat_api_url,omitempty" json:"wechat_api_url,omitempty"`
WeChatAPISecret Secret `yaml:"wechat_api_secret,omitempty" json:"wechat_api_secret,omitempty"`
WeChatAPICorpID string `yaml:"wechat_api_corp_id,omitempty" json:"wechat_api_corp_id,omitempty"`
VictorOpsAPIURL *URL `yaml:"victorops_api_url,omitempty" json:"victorops_api_url,omitempty"`
VictorOpsAPIKey Secret `yaml:"victorops_api_key,omitempty" json:"victorops_api_key,omitempty"`
VictorOpsAPIKeyFile string `yaml:"victorops_api_key_file,omitempty" json:"victorops_api_key_file,omitempty"`
TelegramAPIUrl *URL `yaml:"telegram_api_url,omitempty" json:"telegram_api_url,omitempty"`
WebexAPIURL *URL `yaml:"webex_api_url,omitempty" json:"webex_api_url,omitempty"`
SMTPFrom string `yaml:"smtp_from,omitempty" json:"smtp_from,omitempty"`
SMTPHello string `yaml:"smtp_hello,omitempty" json:"smtp_hello,omitempty"`
SMTPSmarthost HostPort `yaml:"smtp_smarthost,omitempty" json:"smtp_smarthost,omitempty"`
SMTPAuthUsername string `yaml:"smtp_auth_username,omitempty" json:"smtp_auth_username,omitempty"`
SMTPAuthPassword Secret `yaml:"smtp_auth_password,omitempty" json:"smtp_auth_password,omitempty"`
SMTPAuthPasswordFile string `yaml:"smtp_auth_password_file,omitempty" json:"smtp_auth_password_file,omitempty"`
SMTPAuthSecret Secret `yaml:"smtp_auth_secret,omitempty" json:"smtp_auth_secret,omitempty"`
SMTPAuthIdentity string `yaml:"smtp_auth_identity,omitempty" json:"smtp_auth_identity,omitempty"`
SMTPRequireTLS bool `yaml:"smtp_require_tls" json:"smtp_require_tls,omitempty"`
SlackAPIURL *SecretURL `yaml:"slack_api_url,omitempty" json:"slack_api_url,omitempty"`
SlackAPIURLFile string `yaml:"slack_api_url_file,omitempty" json:"slack_api_url_file,omitempty"`
PagerdutyURL *URL `yaml:"pagerduty_url,omitempty" json:"pagerduty_url,omitempty"`
OpsGenieAPIURL *URL `yaml:"opsgenie_api_url,omitempty" json:"opsgenie_api_url,omitempty"`
OpsGenieAPIKey Secret `yaml:"opsgenie_api_key,omitempty" json:"opsgenie_api_key,omitempty"`
OpsGenieAPIKeyFile string `yaml:"opsgenie_api_key_file,omitempty" json:"opsgenie_api_key_file,omitempty"`
WeChatAPIURL *URL `yaml:"wechat_api_url,omitempty" json:"wechat_api_url,omitempty"`
WeChatAPISecret Secret `yaml:"wechat_api_secret,omitempty" json:"wechat_api_secret,omitempty"`
WeChatAPICorpID string `yaml:"wechat_api_corp_id,omitempty" json:"wechat_api_corp_id,omitempty"`
VictorOpsAPIURL *URL `yaml:"victorops_api_url,omitempty" json:"victorops_api_url,omitempty"`
VictorOpsAPIKey Secret `yaml:"victorops_api_key,omitempty" json:"victorops_api_key,omitempty"`
VictorOpsAPIKeyFile string `yaml:"victorops_api_key_file,omitempty" json:"victorops_api_key_file,omitempty"`
TelegramAPIUrl *URL `yaml:"telegram_api_url,omitempty" json:"telegram_api_url,omitempty"`
WebexAPIURL *URL `yaml:"webex_api_url,omitempty" json:"webex_api_url,omitempty"`
DiscordWebhookURL *SecretURL `yaml:"discord_webhook_url,omitempty" json:"discord_webhook_url,omitempty"`
DiscordWebhookURLFile string `yaml:"discord_webhook_url_file,omitempty" json:"discord_webhook_url_file,omitempty"`
}

// UnmarshalYAML implements the yaml.Unmarshaler interface for GlobalConfig.
Expand Down
5 changes: 3 additions & 2 deletions config/notifiers.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,9 @@ func (c *WebexConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
type DiscordConfig struct {
NotifierConfig `yaml:",inline" json:",inline"`

HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`
WebhookURL *SecretURL `yaml:"webhook_url,omitempty" json:"webhook_url,omitempty"`
HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`
WebhookURL *SecretURL `yaml:"webhook_url,omitempty" json:"webhook_url,omitempty"`
WebhookURLFile string `yaml:"webhook_url_file,omitempty" json:"webhook_url_file,omitempty"`

Title string `yaml:"title,omitempty" json:"title,omitempty"`
Message string `yaml:"message,omitempty" json:"message,omitempty"`
Expand Down
9 changes: 8 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ global:
[ wechat_api_corp_id: <string> ]
[ telegram_api_url: <string> | default = "https://api.telegram.org" ]
[ webex_api_url: <string> | default = "https://webexapis.com/v1/messages" ]
[ discord_webhook_url: <secret> ]
[ discord_webhook_url_file: <filepath> ]
# The default HTTP client configuration
[ http_config: <http_config> ]

Expand Down Expand Up @@ -643,7 +645,12 @@ Discord notifications are sent via the [Discord webhook API](https://discord.com
[ send_resolved: <boolean> | default = true ]

# The Discord webhook URL.
webhook_url: <secret>
# It is mutually exclusive with webhook_url_file
[ webhook_url: <secret> | default = global.discord_webhook_url ]

# Read the webhook URL from a file
# It is mutually exclusive with `webhook_url`.
[ webhook_url_file: <filepath> | default = global.discord_webhook_url_file ]

# Message title template.
[ title: <tmpl_string> | default = '{{ template "discord.default.title" . }}' ]
Expand Down
16 changes: 15 additions & 1 deletion notify/discord/discord.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ import (
"context"
"encoding/json"
"net/http"
"os"
"strings"

"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/pkg/errors"
commoncfg "github.com/prometheus/common/config"
"github.com/prometheus/common/model"

Expand Down Expand Up @@ -76,6 +79,17 @@ type webhookEmbed struct {

// Notify implements the Notifier interface.
func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) {
var webhookURL string
if n.conf.WebhookURL != nil {
webhookURL = n.conf.WebhookURL.String()
} else {
content, fileErr := os.ReadFile(n.conf.WebhookURLFile)
if fileErr != nil {
return false, errors.Wrap(fileErr, "failed to read webhook URL from file")
}
webhookURL = strings.TrimSpace(string(content))
}

key, err := notify.ExtractGroupKey(ctx)
if err != nil {
return false, err
Expand Down Expand Up @@ -120,7 +134,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
return false, err
}

resp, err := notify.PostJSON(ctx, n.client, n.webhookURL.String(), &payload)
resp, err := notify.PostJSON(ctx, n.client, webhookURL, &payload)
if err != nil {
return true, notify.RedactURL(err)
}
Expand Down
26 changes: 26 additions & 0 deletions notify/discord/discord_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"net/http"
"net/http/httptest"
"net/url"
"os"
"testing"
"time"

Expand Down Expand Up @@ -127,3 +128,28 @@ func TestDiscordTemplating(t *testing.T) {
})
}
}

func TestGettingDiscordWebhookURLFromFile(t *testing.T) {
ctx, u, fn := test.GetContextWithCancelingURL()
defer fn()

url := "https://discord.com/api/webhooks/123/123"

f, err := os.CreateTemp("", "discord_test")
require.NoError(t, err, "creating temp file failed")
_, err = f.WriteString(url)
require.NoError(t, err, "writing to temp file failed")

notifier, err := New(
&config.DiscordConfig{
WebhookURL: &config.SecretURL{URL: u},
WebhookURLFile: f.Name(),
HTTPConfig: &commoncfg.HTTPClientConfig{},
},
test.CreateTmpl(t),
log.NewNopLogger(),
)
require.NoError(t, err)

test.AssertNotifyLeaksNoSecret(ctx, t, notifier, url)
}