Skip to content

Commit 7780195

Browse files
bishtawiTwiN
andauthored
feat(alerting): Add overrides for Ntfy provider (#918)
* Add overrides to Ntfy alert provider * Update alerting/provider/ntfy/ntfy.go --------- Co-authored-by: TwiN <[email protected]>
1 parent 29cbff6 commit 7780195

File tree

3 files changed

+206
-24
lines changed

3 files changed

+206
-24
lines changed

README.md

+38-13
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ If you want to test it locally, see [Docker](#docker).
240240
| `ui.buttons[].link` | Link to open when the button is clicked. | Required `""` |
241241
| `maintenance` | [Maintenance configuration](#maintenance). | `{}` |
242242

243-
If you want more verbose logging, you may set the `GATUS_LOG_LEVEL` environment variable to `DEBUG`.
243+
If you want more verbose logging, you may set the `GATUS_LOG_LEVEL` environment variable to `DEBUG`.
244244
Conversely, if you want less verbose logging, you can set the aforementioned environment variable to `WARN`, `ERROR` or `FATAL`.
245245
The default value for `GATUS_LOG_LEVEL` is `INFO`.
246246

@@ -987,18 +987,26 @@ endpoints:
987987

988988

989989
#### Configuring Ntfy alerts
990-
| Parameter | Description | Default |
991-
|:---------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------|:------------------|
992-
| `alerting.ntfy` | Configuration for alerts of type `ntfy` | `{}` |
993-
| `alerting.ntfy.topic` | Topic at which the alert will be sent | Required `""` |
994-
| `alerting.ntfy.url` | The URL of the target server | `https://ntfy.sh` |
995-
| `alerting.ntfy.token` | [Access token](https://docs.ntfy.sh/publish/#access-tokens) for restricted topics | `""` |
996-
| `alerting.ntfy.email` | E-mail address for additional e-mail notifications | `""` |
997-
| `alerting.ntfy.click` | Website opened when notification is clicked | `""` |
998-
| `alerting.ntfy.priority` | The priority of the alert | `3` |
999-
| `alerting.ntfy.disable-firebase` | Whether message push delivery via firebase should be disabled. [ntfy.sh defaults to enabled](https://docs.ntfy.sh/publish/#disable-firebase) | `false` |
1000-
| `alerting.ntfy.disable-cache` | Whether server side message caching should be disabled. [ntfy.sh defaults to enabled](https://docs.ntfy.sh/publish/#message-caching) | `false` |
1001-
| `alerting.ntfy.default-alert` | Default alert configuration. <br />See [Setting a default alert](#setting-a-default-alert) | N/A |
990+
| Parameter | Description | Default |
991+
|:-------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------|:------------------|
992+
| `alerting.ntfy` | Configuration for alerts of type `ntfy` | `{}` |
993+
| `alerting.ntfy.topic` | Topic at which the alert will be sent | Required `""` |
994+
| `alerting.ntfy.url` | The URL of the target server | `https://ntfy.sh` |
995+
| `alerting.ntfy.token` | [Access token](https://docs.ntfy.sh/publish/#access-tokens) for restricted topics | `""` |
996+
| `alerting.ntfy.email` | E-mail address for additional e-mail notifications | `""` |
997+
| `alerting.ntfy.click` | Website opened when notification is clicked | `""` |
998+
| `alerting.ntfy.priority` | The priority of the alert | `3` |
999+
| `alerting.ntfy.disable-firebase` | Whether message push delivery via firebase should be disabled. [ntfy.sh defaults to enabled](https://docs.ntfy.sh/publish/#disable-firebase) | `false` |
1000+
| `alerting.ntfy.disable-cache` | Whether server side message caching should be disabled. [ntfy.sh defaults to enabled](https://docs.ntfy.sh/publish/#message-caching) | `false` |
1001+
| `alerting.ntfy.default-alert` | Default alert configuration. <br />See [Setting a default alert](#setting-a-default-alert) | N/A |
1002+
| `alerting.ntfy.overrides` | List of overrides that may be prioritized over the default configuration | `[]` |
1003+
| `alerting.ntfy.overrides[].group` | Endpoint group for which the configuration will be overridden by this configuration | `""` |
1004+
| `alerting.ntfy.overrides[].topic` | Topic at which the alert will be sent | `""` |
1005+
| `alerting.ntfy.overrides[].url` | The URL of the target server | `""` |
1006+
| `alerting.ntfy.overrides[].priority` | The priority of the alert | `0` |
1007+
| `alerting.ntfy.overrides[].token` | Access token for restricted topics | `""` |
1008+
| `alerting.ntfy.overrides[].email` | E-mail address for additional e-mail notifications | `""` |
1009+
| `alerting.ntfy.overrides[].click` | Website opened when notification is clicked | `""` |
10021010

10031011
[ntfy](https://github.com/binwiederhier/ntfy) is an amazing project that allows you to subscribe to desktop
10041012
and mobile notifications, making it an awesome addition to Gatus.
@@ -1013,6 +1021,13 @@ alerting:
10131021
default-alert:
10141022
failure-threshold: 3
10151023
send-on-resolved: true
1024+
# You can also add group-specific to keys, which will
1025+
# override the to key above for the specified groups
1026+
overrides:
1027+
- group: "other"
1028+
topic: "gatus-other-test-topic"
1029+
priority: 4
1030+
click: "https://example.com"
10161031
10171032
endpoints:
10181033
- name: website
@@ -1024,6 +1039,16 @@ endpoints:
10241039
- "[RESPONSE_TIME] < 300"
10251040
alerts:
10261041
- type: ntfy
1042+
- name: other example
1043+
group: other
1044+
interval: 30m
1045+
url: "https://example.com"
1046+
conditions:
1047+
- "[STATUS] == 200"
1048+
- "[BODY].status == UP"
1049+
alerts:
1050+
- type: ntfy
1051+
description: example
10271052
```
10281053

10291054

alerting/provider/ntfy/ntfy.go

+99-10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
const (
1818
DefaultURL = "https://ntfy.sh"
1919
DefaultPriority = 3
20+
TokenPrefix = "tk_"
2021
)
2122

2223
// AlertProvider is the configuration necessary for sending an alert using Slack
@@ -32,6 +33,20 @@ type AlertProvider struct {
3233

3334
// DefaultAlert is the default alert configuration to use for endpoints with an alert of the appropriate type
3435
DefaultAlert *alert.Alert `yaml:"default-alert,omitempty"`
36+
37+
// Overrides is a list of Override that may be prioritized over the default configuration
38+
Overrides []Override `yaml:"overrides,omitempty"`
39+
}
40+
41+
// Override is a case under which the default integration is overridden
42+
type Override struct {
43+
Group string `yaml:"group"`
44+
Topic string `yaml:"topic"`
45+
URL string `yaml:"url"`
46+
Priority int `yaml:"priority"`
47+
Token string `yaml:"token"`
48+
Email string `yaml:"email"`
49+
Click string `yaml:"click"`
3550
}
3651

3752
// IsValid returns whether the provider's configuration is valid
@@ -44,21 +59,42 @@ func (provider *AlertProvider) IsValid() bool {
4459
}
4560
isTokenValid := true
4661
if len(provider.Token) > 0 {
47-
isTokenValid = strings.HasPrefix(provider.Token, "tk_")
62+
isTokenValid = strings.HasPrefix(provider.Token, TokenPrefix)
63+
}
64+
registeredGroups := make(map[string]bool)
65+
if provider.Overrides != nil {
66+
for _, override := range provider.Overrides {
67+
if len(override.Group) == 0 {
68+
return false
69+
}
70+
if _, ok := registeredGroups[override.Group]; ok {
71+
return false
72+
}
73+
if len(override.Token) > 0 && !strings.HasPrefix(override.Token, TokenPrefix) {
74+
return false
75+
}
76+
if override.Priority < 0 || override.Priority >= 6 {
77+
return false
78+
}
79+
registeredGroups[override.Group] = true
80+
}
4881
}
82+
4983
return len(provider.URL) > 0 && len(provider.Topic) > 0 && provider.Priority > 0 && provider.Priority < 6 && isTokenValid
5084
}
5185

5286
// Send an alert using the provider
5387
func (provider *AlertProvider) Send(ep *endpoint.Endpoint, alert *alert.Alert, result *endpoint.Result, resolved bool) error {
54-
buffer := bytes.NewBuffer(provider.buildRequestBody(ep, alert, result, resolved))
55-
request, err := http.NewRequest(http.MethodPost, provider.URL, buffer)
88+
override := provider.getGroupOverride(ep.Group)
89+
buffer := bytes.NewBuffer(provider.buildRequestBody(ep, alert, result, resolved, override))
90+
url := provider.getURL(override)
91+
request, err := http.NewRequest(http.MethodPost, url, buffer)
5692
if err != nil {
5793
return err
5894
}
5995
request.Header.Set("Content-Type", "application/json")
60-
if len(provider.Token) > 0 {
61-
request.Header.Set("Authorization", "Bearer "+provider.Token)
96+
if token := provider.getToken(override); len(token) > 0 {
97+
request.Header.Set("Authorization", "Bearer "+token)
6298
}
6399
if provider.DisableFirebase {
64100
request.Header.Set("Firebase", "no")
@@ -89,7 +125,7 @@ type Body struct {
89125
}
90126

91127
// buildRequestBody builds the request body for the provider
92-
func (provider *AlertProvider) buildRequestBody(ep *endpoint.Endpoint, alert *alert.Alert, result *endpoint.Result, resolved bool) []byte {
128+
func (provider *AlertProvider) buildRequestBody(ep *endpoint.Endpoint, alert *alert.Alert, result *endpoint.Result, resolved bool, override *Override) []byte {
93129
var message, formattedConditionResults, tag string
94130
if resolved {
95131
tag = "white_check_mark"
@@ -112,13 +148,13 @@ func (provider *AlertProvider) buildRequestBody(ep *endpoint.Endpoint, alert *al
112148
}
113149
message += formattedConditionResults
114150
body, _ := json.Marshal(Body{
115-
Topic: provider.Topic,
151+
Topic: provider.getTopic(override),
116152
Title: "Gatus: " + ep.DisplayName(),
117153
Message: message,
118154
Tags: []string{tag},
119-
Priority: provider.Priority,
120-
Email: provider.Email,
121-
Click: provider.Click,
155+
Priority: provider.getPriority(override),
156+
Email: provider.getEmail(override),
157+
Click: provider.getClick(override),
122158
})
123159
return body
124160
}
@@ -127,3 +163,56 @@ func (provider *AlertProvider) buildRequestBody(ep *endpoint.Endpoint, alert *al
127163
func (provider *AlertProvider) GetDefaultAlert() *alert.Alert {
128164
return provider.DefaultAlert
129165
}
166+
167+
func (provider *AlertProvider) getGroupOverride(group string) *Override {
168+
if provider.Overrides != nil {
169+
for _, override := range provider.Overrides {
170+
if group == override.Group {
171+
return &override
172+
}
173+
}
174+
}
175+
return nil
176+
}
177+
178+
func (provider *AlertProvider) getTopic(override *Override) string {
179+
if override != nil && len(override.Topic) > 0 {
180+
return override.Topic
181+
}
182+
return provider.Topic
183+
}
184+
185+
func (provider *AlertProvider) getURL(override *Override) string {
186+
if override != nil && len(override.URL) > 0 {
187+
return override.URL
188+
}
189+
return provider.URL
190+
}
191+
192+
func (provider *AlertProvider) getPriority(override *Override) int {
193+
if override != nil && override.Priority > 0 {
194+
return override.Priority
195+
}
196+
return provider.Priority
197+
}
198+
199+
func (provider *AlertProvider) getToken(override *Override) string {
200+
if override != nil && len(override.Token) > 0 {
201+
return override.Token
202+
}
203+
return provider.Token
204+
}
205+
206+
func (provider *AlertProvider) getEmail(override *Override) string {
207+
if override != nil && len(override.Email) > 0 {
208+
return override.Email
209+
}
210+
return provider.Email
211+
}
212+
213+
func (provider *AlertProvider) getClick(override *Override) string {
214+
if override != nil && len(override.Click) > 0 {
215+
return override.Click
216+
}
217+
return provider.Click
218+
}

0 commit comments

Comments
 (0)