Skip to content
This repository was archived by the owner on Mar 14, 2025. It is now read-only.

Commit 409a76c

Browse files
authored
feat: add telegram alert channel (#28)
1 parent da75d4b commit 409a76c

23 files changed

+723
-96
lines changed

api/api.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,10 @@ func New(opts Options) (*API, error) {
173173
// true for the concurrency limit, with the exception that it is only applied to
174174
// GET requests.
175175
func (api *API) Register(r *route.Router, routePrefix string, reloadCh chan<- chan error, updateConfigCh chan interface{}, updateConfigErrCh chan error) *http.ServeMux {
176-
176+
177177
// reloadCh: can initiate reload of alertmanager with updated config
178178
// on request
179-
// updateConfigCh: writes current config from memory to disk
179+
// updateConfigCh: writes current config from memory to disk
180180
api.v1.Register(r.WithPrefix("/api/v1"), reloadCh, updateConfigCh, updateConfigErrCh)
181181

182182
mux := http.NewServeMux()

api/v1/config_api.go

+18
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/prometheus/alertmanager/notify/opsgenie"
1717
"github.com/prometheus/alertmanager/notify/pagerduty"
1818
"github.com/prometheus/alertmanager/notify/slack"
19+
"github.com/prometheus/alertmanager/notify/telegram"
1920
"github.com/prometheus/alertmanager/notify/webhook"
2021
"github.com/prometheus/alertmanager/template"
2122
"github.com/prometheus/alertmanager/types"
@@ -297,6 +298,23 @@ func (api *API) testReceiver(w http.ResponseWriter, req *http.Request) {
297298
api.respondError(w, apiError{err: err, typ: errorInternal}, fmt.Sprintf("failed to send test message to channel (%s)", receiver.Name))
298299
return
299300
}
301+
} else if receiver.TelegramConfigs != nil {
302+
telegramConfig := receiver.TelegramConfigs[0]
303+
telegramConfig.HTTPConfig = &commoncfg.HTTPClientConfig{}
304+
telegramConfig.APIUrl = defaultGlobalConfig.TelegramAPIUrl
305+
telegramConfig.ParseMode = "HTML"
306+
notifier, err := telegram.New(telegramConfig, tmpl, api.logger)
307+
if err != nil {
308+
api.respondError(w, apiError{err: err, typ: errorInternal}, "failed to prepare message for select config")
309+
return
310+
}
311+
ctx := getCtx(receiver.Name)
312+
dummyAlert := getDummyAlert()
313+
_, err = notifier.Notify(ctx, &dummyAlert)
314+
if err != nil {
315+
api.respondError(w, apiError{err: err, typ: errorInternal}, fmt.Sprintf("failed to send test message to channel (%s)", receiver.Name))
316+
}
317+
return
300318
} else if receiver.EmailConfigs != nil {
301319
emailConfig := receiver.EmailConfigs[0]
302320
emailConfig.From = defaultGlobalConfig.SMTPFrom

asset/asset.go

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
// See the License for the specific language governing permissions and
1212
// limitations under the License.
1313

14+
//go:build dev
1415
// +build dev
1516

1617
package asset

asset/asset_generate.go

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
// See the License for the specific language governing permissions and
1212
// limitations under the License.
1313

14+
//go:build ignore
1415
// +build ignore
1516

1617
package main

asset/assets_vfsdata.go

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/alertmanager/main.go

+4
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ import (
5656
"github.com/prometheus/alertmanager/notify/pushover"
5757
"github.com/prometheus/alertmanager/notify/slack"
5858
"github.com/prometheus/alertmanager/notify/sns"
59+
"github.com/prometheus/alertmanager/notify/telegram"
5960
"github.com/prometheus/alertmanager/notify/victorops"
6061
"github.com/prometheus/alertmanager/notify/webhook"
6162
"github.com/prometheus/alertmanager/notify/wechat"
@@ -158,6 +159,9 @@ func buildReceiverIntegrations(nc *config.Receiver, tmpl *template.Template, log
158159
for i, c := range nc.OpsGenieConfigs {
159160
add("opsgenie", i, c, func(l log.Logger) (notify.Notifier, error) { return opsgenie.New(c, tmpl, l) })
160161
}
162+
for i, c := range nc.TelegramConfigs {
163+
add("telegram", i, c, func(l log.Logger) (notify.Notifier, error) { return telegram.New(c, tmpl, l) })
164+
}
161165
for i, c := range nc.WechatConfigs {
162166
add("wechat", i, c, func(l log.Logger) (notify.Notifier, error) { return wechat.New(c, tmpl, l) })
163167
}

config/config.go

+14
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ func resolveFilepaths(baseDir string, cfg *Config) {
228228
for _, cfg := range receiver.OpsGenieConfigs {
229229
cfg.HTTPConfig.SetDirectory(baseDir)
230230
}
231+
for _, cfg := range receiver.TelegramConfigs {
232+
cfg.HTTPConfig.SetDirectory(baseDir)
233+
}
231234
for _, cfg := range receiver.PagerdutyConfigs {
232235
cfg.HTTPConfig.SetDirectory(baseDir)
233236
}
@@ -511,6 +514,14 @@ func (c *Config) Validate() error {
511514
ogc.APIKeyFile = c.Global.OpsGenieAPIKeyFile
512515
}
513516
}
517+
for _, telegram := range rcv.TelegramConfigs {
518+
if telegram.HTTPConfig == nil {
519+
telegram.HTTPConfig = c.Global.HTTPConfig
520+
}
521+
if telegram.APIUrl == nil {
522+
telegram.APIUrl = c.Global.TelegramAPIUrl
523+
}
524+
}
514525
for _, wcc := range rcv.WechatConfigs {
515526
if wcc.HTTPConfig == nil {
516527
wcc.HTTPConfig = c.Global.HTTPConfig
@@ -770,6 +781,7 @@ func DefaultGlobalConfig() GlobalConfig {
770781
SMTPRequireTLS: true,
771782
PagerdutyURL: mustParseURL("https://events.pagerduty.com/v2/enqueue"),
772783
OpsGenieAPIURL: mustParseURL("https://api.opsgenie.com/"),
784+
TelegramAPIUrl: mustParseURL("https://api.telegram.org"),
773785
WeChatAPIURL: mustParseURL("https://qyapi.weixin.qq.com/cgi-bin/"),
774786
VictorOpsAPIURL: mustParseURL("https://alert.victorops.com/integrations/generic/20131114/alert/"),
775787
}
@@ -889,6 +901,7 @@ type GlobalConfig struct {
889901
OpsGenieAPIURL *URL `yaml:"opsgenie_api_url,omitempty" json:"opsgenie_api_url,omitempty"`
890902
OpsGenieAPIKey Secret `yaml:"opsgenie_api_key,omitempty" json:"opsgenie_api_key,omitempty"`
891903
OpsGenieAPIKeyFile string `yaml:"opsgenie_api_key_file,omitempty" json:"opsgenie_api_key_file,omitempty"`
904+
TelegramAPIUrl *URL `yaml:"telegram_api_url,omitempty" json:"telegram_api_url,omitempty"`
892905
WeChatAPIURL *URL `yaml:"wechat_api_url,omitempty" json:"wechat_api_url,omitempty"`
893906
WeChatAPISecret Secret `yaml:"wechat_api_secret,omitempty" json:"wechat_api_secret,omitempty"`
894907
WeChatAPICorpID string `yaml:"wechat_api_corp_id,omitempty" json:"wechat_api_corp_id,omitempty"`
@@ -1052,6 +1065,7 @@ type Receiver struct {
10521065
SlackConfigs []*SlackConfig `yaml:"slack_configs,omitempty" json:"slack_configs,omitempty"`
10531066
WebhookConfigs []*WebhookConfig `yaml:"webhook_configs,omitempty" json:"webhook_configs,omitempty"`
10541067
OpsGenieConfigs []*OpsGenieConfig `yaml:"opsgenie_configs,omitempty" json:"opsgenie_configs,omitempty"`
1068+
TelegramConfigs []*TelegramConfig `yaml:"telegram_configs,omitempty" json:"telegram_configs,omitempty"`
10551069
WechatConfigs []*WechatConfig `yaml:"wechat_configs,omitempty" json:"wechat_configs,omitempty"`
10561070
PushoverConfigs []*PushoverConfig `yaml:"pushover_configs,omitempty" json:"pushover_configs,omitempty"`
10571071
VictorOpsConfigs []*VictorOpsConfig `yaml:"victorops_configs,omitempty" json:"victorops_configs,omitempty"`

config/config_loader.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
package config
22

33
import (
4+
"gopkg.in/yaml.v2"
45
"io/ioutil"
56
"path/filepath"
6-
"gopkg.in/yaml.v2"
77
)
88

99
// ConfigLoader loads config for co-ordinator
1010
type ConfigLoader interface {
1111
Load(c *Config) error
1212
}
1313

14-
1514
// configFileLoader is default config loader that reads
1615
// from yaml file. This is primarily meant for test coverage
1716
type configFileLoader struct {
@@ -34,9 +33,8 @@ func (cfl *configFileLoader) Load(c *Config) error {
3433
if err != nil {
3534
return err
3635
}
37-
36+
3837
c.original = string(content)
3938
resolveFilepaths(filepath.Dir(cfl.filePath), c)
4039
return c.Validate()
4140
}
42-

config/config_requests.go

+10-9
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,26 @@ import "fmt"
44

55
const (
66
AddRouteAction = iota + 1
7-
EditRouteAction
8-
DeleteRouteAction
7+
EditRouteAction
8+
DeleteRouteAction
99
)
10+
1011
// ConfigChangeRequest is useful when managing configuration changes
1112
type ConfigChangeRequest struct {
12-
Action int
13-
Route *Route
13+
Action int
14+
Route *Route
1415
Receiver *Receiver
1516
}
1617

17-
func (c *ConfigChangeRequest) Validate() error {
18+
func (c *ConfigChangeRequest) Validate() error {
1819
if c.Action == 0 {
1920
return fmt.Errorf("action field must be set for validating config change request")
2021
}
2122

2223
switch c.Action {
23-
case AddRouteAction, EditRouteAction:
24-
return c.Receiver.Validate()
25-
default:
26-
return nil
24+
case AddRouteAction, EditRouteAction:
25+
return c.Receiver.Validate()
26+
default:
27+
return nil
2728
}
2829
}

config/config_test.go

+19-18
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ import (
2525

2626
commoncfg "github.com/prometheus/common/config"
2727
"github.com/prometheus/common/model"
28-
"github.com/stretchr/testify/require"
2928
"github.com/stretchr/testify/assert"
29+
"github.com/stretchr/testify/require"
3030
"gopkg.in/yaml.v2"
3131
)
3232

@@ -445,8 +445,9 @@ receivers:
445445
t.Errorf("\nexpected:\n%q\ngot:\n%q", expected, err.Error())
446446
}
447447
}
448-
/* Amol/SigNoz 21/03/22 Skipping this test
449-
as we need to keep the secrets in memory to support dynamic changes
448+
449+
/* Amol/SigNoz 21/03/22 Skipping this test
450+
as we need to keep the secrets in memory to support dynamic changes
450451
451452
func TestHideConfigSecrets(t *testing.T) {
452453
c, err := LoadFile("testdata/conf.good.yml")
@@ -1167,59 +1168,59 @@ func TestAddAndDeleteRoute(t *testing.T) {
11671168
Receiver: "test-add-route",
11681169
}
11691170

1170-
receiver := Receiver {
1171+
receiver := Receiver{
11711172
Name: "test-add-route",
11721173
WebhookConfigs: []*WebhookConfig{
1173-
&WebhookConfig {
1174+
&WebhookConfig{
11741175
URL: (*URL)(mustParseURL("https://webhook")),
11751176
},
11761177
},
11771178
}
11781179

11791180
config.AddRoute(&route, &receiver)
1180-
1181+
11811182
assert := assert.New(t)
11821183
assert.NotNil(t, config)
11831184
if assert.NotNil(t, config.Route) {
11841185
if assert.NotNil(t, config.Route.Routes) {
1185-
expectedRoutes := []*Route {
1186+
expectedRoutes := []*Route{
11861187
&route,
11871188
}
1188-
1189+
11891190
assert.Equal(config.Route.Routes, expectedRoutes, "unexpected attributes found on route")
11901191
}
11911192
}
1192-
1193+
11931194
if assert.NotNil(t, config.Receivers) {
11941195
if assert.Equal(len(config.Receivers), 2, "unexpected receivers found") {
11951196
assert.Equal(config.Receivers[1], &receiver, "unexpected attributes found on the receiver")
11961197
}
11971198
}
1198-
1199+
11991200
route.Receiver = "test-add-route-2"
12001201
receiver.Name = "test-add-route-2"
12011202

12021203
config.AddRoute(&route, &receiver)
12031204

12041205
assert.NoError(config.DeleteRoute("test-add-route"), "failed to delete route test-add-route")
1205-
1206-
// check if existing receiver still exists
1206+
1207+
// check if existing receiver still exists
12071208
check1 := false
12081209

1209-
// check if deleted receiver does not eixst
1210+
// check if deleted receiver does not eixst
12101211
check2 := true
1211-
1212+
12121213
for _, r := range config.Receivers {
12131214
if r.Name == "test-add-route-2" {
1214-
check1 = true;
1215+
check1 = true
12151216
}
1216-
if r.Name == "test-add-route"{
1217-
// deleted receiver exists
1217+
if r.Name == "test-add-route" {
1218+
// deleted receiver exists
12181219
check2 = false
12191220
}
12201221
}
12211222

12221223
assert.Equal(check1, true, "existing route deleted even when not asked")
12231224
assert.Equal(check2, true, "deleted receiver still exists")
12241225
assert.Equal(config.Route.Routes[0], &route, "deleting route did not work")
1225-
}
1226+
}

0 commit comments

Comments
 (0)