Skip to content

Commit 525a555

Browse files
tamcoreth0th
authored andcommitted
feat: implement webhook_url_file for discord and msteams (prometheus#3555)
* feat: implement webhook_url_file for discord implements prometheus#3482 Signed-off-by: Philipp Born <[email protected]> * feat: implement webhook_url_file for msteams implements prometheus#3536 Signed-off-by: Philipp Born <[email protected]> --------- Signed-off-by: Philipp Born <[email protected]> Signed-off-by: Gokhan Sari <[email protected]>
1 parent 608c5a4 commit 525a555

File tree

6 files changed

+146
-6
lines changed

6 files changed

+146
-6
lines changed

config/notifiers.go

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,9 @@ func (c *WebexConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
216216
type DiscordConfig struct {
217217
NotifierConfig `yaml:",inline" json:",inline"`
218218

219-
HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`
220-
WebhookURL *SecretURL `yaml:"webhook_url,omitempty" json:"webhook_url,omitempty"`
219+
HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`
220+
WebhookURL *SecretURL `yaml:"webhook_url,omitempty" json:"webhook_url,omitempty"`
221+
WebhookURLFile string `yaml:"webhook_url_file,omitempty" json:"webhook_url_file,omitempty"`
221222

222223
Title string `yaml:"title,omitempty" json:"title,omitempty"`
223224
Message string `yaml:"message,omitempty" json:"message,omitempty"`
@@ -227,7 +228,19 @@ type DiscordConfig struct {
227228
func (c *DiscordConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
228229
*c = DefaultDiscordConfig
229230
type plain DiscordConfig
230-
return unmarshal((*plain)(c))
231+
if err := unmarshal((*plain)(c)); err != nil {
232+
return err
233+
}
234+
235+
if c.WebhookURL == nil && c.WebhookURLFile == "" {
236+
return fmt.Errorf("one of webhook_url or webhook_url_file must be configured")
237+
}
238+
239+
if c.WebhookURL != nil && len(c.WebhookURLFile) > 0 {
240+
return fmt.Errorf("at most one of webhook_url & webhook_url_file must be configured")
241+
}
242+
243+
return nil
231244
}
232245

233246
// EmailConfig configures notifications via mail.
@@ -788,6 +801,7 @@ type MSTeamsConfig struct {
788801
NotifierConfig `yaml:",inline" json:",inline"`
789802
HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`
790803
WebhookURL *SecretURL `yaml:"webhook_url,omitempty" json:"webhook_url,omitempty"`
804+
WebhookURLFile string `yaml:"webhook_url_file,omitempty" json:"webhook_url_file,omitempty"`
791805

792806
Title string `yaml:"title,omitempty" json:"title,omitempty"`
793807
Summary string `yaml:"summary,omitempty" json:"summary,omitempty"`
@@ -797,5 +811,17 @@ type MSTeamsConfig struct {
797811
func (c *MSTeamsConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
798812
*c = DefaultMSTeamsConfig
799813
type plain MSTeamsConfig
800-
return unmarshal((*plain)(c))
814+
if err := unmarshal((*plain)(c)); err != nil {
815+
return err
816+
}
817+
818+
if c.WebhookURL == nil && c.WebhookURLFile == "" {
819+
return fmt.Errorf("one of webhook_url or webhook_url_file must be configured")
820+
}
821+
822+
if c.WebhookURL != nil && len(c.WebhookURLFile) > 0 {
823+
return fmt.Errorf("at most one of webhook_url & webhook_url_file must be configured")
824+
}
825+
826+
return nil
801827
}

docs/configuration.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,9 @@ Discord notifications are sent via the [Discord webhook API](https://discord.com
670670
[ send_resolved: <boolean> | default = true ]
671671
672672
# The Discord webhook URL.
673+
# webhook_url and webhook_url_file are mutually exclusive.
673674
webhook_url: <secret>
675+
webhook_url_file: <filepath>
674676
675677
# Message title template.
676678
[ title: <tmpl_string> | default = '{{ template "discord.default.title" . }}' ]
@@ -735,7 +737,9 @@ Microsoft Teams notifications are sent via the [Incoming Webhooks](https://learn
735737
[ send_resolved: <boolean> | default = true ]
736738
737739
# The incoming webhook URL.
740+
# webhook_url and webhook_url_file are mutually exclusive.
738741
[ webhook_url: <secret> ]
742+
[ webhook_url_file: <filepath> ]
739743
740744
# Message title template.
741745
[ title: <tmpl_string> | default = '{{ template "msteams.default.title" . }}' ]

notify/discord/discord.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ import (
1717
"bytes"
1818
"context"
1919
"encoding/json"
20+
"fmt"
2021
"net/http"
22+
"os"
23+
"strings"
2124

2225
"github.com/go-kit/log"
2326
"github.com/go-kit/log/level"
@@ -120,6 +123,17 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
120123
color = colorGreen
121124
}
122125

126+
var url string
127+
if n.conf.WebhookURL != nil {
128+
url = n.conf.WebhookURL.String()
129+
} else {
130+
content, err := os.ReadFile(n.conf.WebhookURLFile)
131+
if err != nil {
132+
return false, fmt.Errorf("read webhook_url_file: %w", err)
133+
}
134+
url = strings.TrimSpace(string(content))
135+
}
136+
123137
w := webhook{
124138
Embeds: []webhookEmbed{{
125139
Title: title,
@@ -133,7 +147,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
133147
return false, err
134148
}
135149

136-
resp, err := notify.PostJSON(ctx, n.client, n.webhookURL.String(), &payload)
150+
resp, err := notify.PostJSON(ctx, n.client, url, &payload)
137151
if err != nil {
138152
return true, notify.RedactURL(err)
139153
}

notify/discord/discord_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"net/http"
2121
"net/http/httptest"
2222
"net/url"
23+
"os"
2324
"testing"
2425
"time"
2526

@@ -127,3 +128,43 @@ func TestDiscordTemplating(t *testing.T) {
127128
})
128129
}
129130
}
131+
132+
func TestDiscordRedactedURL(t *testing.T) {
133+
ctx, u, fn := test.GetContextWithCancelingURL()
134+
defer fn()
135+
136+
secret := "secret"
137+
notifier, err := New(
138+
&config.DiscordConfig{
139+
WebhookURL: &config.SecretURL{URL: u},
140+
HTTPConfig: &commoncfg.HTTPClientConfig{},
141+
},
142+
test.CreateTmpl(t),
143+
log.NewNopLogger(),
144+
)
145+
require.NoError(t, err)
146+
147+
test.AssertNotifyLeaksNoSecret(ctx, t, notifier, secret)
148+
}
149+
150+
func TestDiscordReadingURLFromFile(t *testing.T) {
151+
ctx, u, fn := test.GetContextWithCancelingURL()
152+
defer fn()
153+
154+
f, err := os.CreateTemp("", "webhook_url")
155+
require.NoError(t, err, "creating temp file failed")
156+
_, err = f.WriteString(u.String() + "\n")
157+
require.NoError(t, err, "writing to temp file failed")
158+
159+
notifier, err := New(
160+
&config.DiscordConfig{
161+
WebhookURLFile: f.Name(),
162+
HTTPConfig: &commoncfg.HTTPClientConfig{},
163+
},
164+
test.CreateTmpl(t),
165+
log.NewNopLogger(),
166+
)
167+
require.NoError(t, err)
168+
169+
test.AssertNotifyLeaksNoSecret(ctx, t, notifier, u.String())
170+
}

notify/msteams/msteams.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@ import (
1717
"bytes"
1818
"context"
1919
"encoding/json"
20+
"fmt"
2021
"io"
2122
"net/http"
23+
"os"
24+
"strings"
2225

2326
"github.com/go-kit/log"
2427
"github.com/go-kit/log/level"
@@ -113,6 +116,17 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
113116
color = colorGreen
114117
}
115118

119+
var url string
120+
if n.conf.WebhookURL != nil {
121+
url = n.conf.WebhookURL.String()
122+
} else {
123+
content, err := os.ReadFile(n.conf.WebhookURLFile)
124+
if err != nil {
125+
return false, fmt.Errorf("read webhook_url_file: %w", err)
126+
}
127+
url = strings.TrimSpace(string(content))
128+
}
129+
116130
t := teamsMessage{
117131
Context: "http://schema.org/extensions",
118132
Type: "MessageCard",
@@ -127,7 +141,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
127141
return false, err
128142
}
129143

130-
resp, err := n.postJSONFunc(ctx, n.client, n.webhookURL.String(), &payload)
144+
resp, err := n.postJSONFunc(ctx, n.client, url, &payload)
131145
if err != nil {
132146
return true, notify.RedactURL(err)
133147
}

notify/msteams/msteams_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"net/http"
2222
"net/http/httptest"
2323
"net/url"
24+
"os"
2425
"testing"
2526
"time"
2627

@@ -192,3 +193,43 @@ func TestNotifier_Notify_WithReason(t *testing.T) {
192193
})
193194
}
194195
}
196+
197+
func TestMSTeamsRedactedURL(t *testing.T) {
198+
ctx, u, fn := test.GetContextWithCancelingURL()
199+
defer fn()
200+
201+
secret := "secret"
202+
notifier, err := New(
203+
&config.MSTeamsConfig{
204+
WebhookURL: &config.SecretURL{URL: u},
205+
HTTPConfig: &commoncfg.HTTPClientConfig{},
206+
},
207+
test.CreateTmpl(t),
208+
log.NewNopLogger(),
209+
)
210+
require.NoError(t, err)
211+
212+
test.AssertNotifyLeaksNoSecret(ctx, t, notifier, secret)
213+
}
214+
215+
func TestMSTeamsReadingURLFromFile(t *testing.T) {
216+
ctx, u, fn := test.GetContextWithCancelingURL()
217+
defer fn()
218+
219+
f, err := os.CreateTemp("", "webhook_url")
220+
require.NoError(t, err, "creating temp file failed")
221+
_, err = f.WriteString(u.String() + "\n")
222+
require.NoError(t, err, "writing to temp file failed")
223+
224+
notifier, err := New(
225+
&config.MSTeamsConfig{
226+
WebhookURLFile: f.Name(),
227+
HTTPConfig: &commoncfg.HTTPClientConfig{},
228+
},
229+
test.CreateTmpl(t),
230+
log.NewNopLogger(),
231+
)
232+
require.NoError(t, err)
233+
234+
test.AssertNotifyLeaksNoSecret(ctx, t, notifier, u.String())
235+
}

0 commit comments

Comments
 (0)