Skip to content

Commit

Permalink
Add feishu notify method
Browse files Browse the repository at this point in the history
  • Loading branch information
HuckOps committed Dec 23, 2024
1 parent 3b61ae8 commit fcdd308
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 224 deletions.
2 changes: 1 addition & 1 deletion asset/assets_vfsdata.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,9 @@ func resolveFilepaths(baseDir string, cfg *Config) {
for _, cfg := range receiver.RocketchatConfigs {
cfg.HTTPConfig.SetDirectory(baseDir)
}
for _, cfg := range receiver.FeishuConfigs {
cfg.HTTPConfig.SetDirectory(baseDir)
}
}
}

Expand Down Expand Up @@ -606,6 +609,29 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
rocketchat.TokenFile = c.Global.RocketchatTokenFile
}
}
for _, feishu := range rcv.FeishuConfigs {
if feishu.HTTPConfig == nil {
feishu.HTTPConfig = c.Global.HTTPConfig
}
if feishu.APIURL == nil {
if c.Global.FeishuAPIURL == nil {
return errors.New("no global FeishuAPIURL set ")
}
feishu.APIURL = c.Global.FeishuAPIURL
}
if feishu.APPID == "" {
if c.Global.FeishuAPPID == "" {
return errors.New("no global FeishuAPPID set ")
}
feishu.APPID = c.Global.FeishuAPPID
}
if feishu.APPSecret == "" {
if c.Global.FeishuAPPSecret == "" {
return errors.New("no global FeishuAPPSecret set ")
}
feishu.APPSecret = c.Global.FeishuAPPSecret
}
}

names[rcv.Name] = struct{}{}
}
Expand Down Expand Up @@ -710,6 +736,7 @@ func DefaultGlobalConfig() GlobalConfig {
TelegramAPIUrl: mustParseURL("https://api.telegram.org"),
WebexAPIURL: mustParseURL("https://webexapis.com/v1/messages"),
RocketchatAPIURL: mustParseURL("https://open.rocket.chat/"),
FeishuAPIURL: mustParseURL("https://open.feishu.cn/open-apis"),
}
}

Expand Down Expand Up @@ -831,6 +858,9 @@ type GlobalConfig struct {
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"`
FeishuAPIURL *URL `yaml:"feishu_api_url,omitempty" json:"feishu_api_url,omitempty"`
FeishuAPPID string `yaml:"feishu_app_id,omitempty" json:"feishu_app_id,omitempty"`
FeishuAPPSecret Secret `yaml:"feishu_app_secret,omitempty" json:"feishu_app_secret,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"`
Expand Down Expand Up @@ -988,6 +1018,7 @@ type Receiver struct {
MSTeamsV2Configs []*MSTeamsV2Config `yaml:"msteamsv2_configs,omitempty" json:"msteamsv2_configs,omitempty"`
JiraConfigs []*JiraConfig `yaml:"jira_configs,omitempty" json:"jira_configs,omitempty"`
RocketchatConfigs []*RocketchatConfig `yaml:"rocketchat_configs,omitempty" json:"rocketchat_configs,omitempty"`
FeishuConfigs []*FeishuConfig `yaml:"feishu_configs,omitempty" json:"feishu_configs,omitempty"`
}

// UnmarshalYAML implements the yaml.Unmarshaler interface for Receiver.
Expand Down
32 changes: 32 additions & 0 deletions config/notifiers.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,15 @@ var (
Description: `{{ template "jira.default.description" . }}`,
Priority: `{{ template "jira.default.priority" . }}`,
}

DefaultFeishuConfig = FeishuConfig{
NotifierConfig: NotifierConfig{
VSendResolved: true,
},
ToUser: `{{ template "feishu.default.to_user" . }}`,
ToChat: `{{ template "feishu.default.to_chat" . }}`,
Message: `{{ template "feishu.default.message" . }}`,
}
)

// NotifierConfig contains base options common across all notifier configurations.
Expand Down Expand Up @@ -597,6 +606,29 @@ func (c *WechatConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
return nil
}

// FeishuConfig configures notifications via Feishu.
type FeishuConfig struct {
NotifierConfig `yaml:",inline" json:",inline"`

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

APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"`
APPID string `yaml:"app_id,omitempty" json:"app_id,omitempty"`
APPSecret Secret `yaml:"app_secret,omitempty" json:"app_secret,omitempty"`
ToUser string `yaml:"to_user,omitempty" json:"to_user,omitempty"`
ToChat string `yaml:"to_chat,omitempty" json:"to_chat,omitempty"`
Message string `yaml:"message,omitempty" json:"message,omitempty"`
}

func (c *FeishuConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
*c = DefaultFeishuConfig
type plain FeishuConfig
if err := unmarshal((*plain)(c)); err != nil {
return err
}
return nil
}

// OpsGenieConfig configures notifications via OpsGenie.
type OpsGenieConfig struct {
NotifierConfig `yaml:",inline" json:",inline"`
Expand Down
5 changes: 4 additions & 1 deletion config/receiver/receiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/prometheus/alertmanager/notify"
"github.com/prometheus/alertmanager/notify/discord"
"github.com/prometheus/alertmanager/notify/email"
"github.com/prometheus/alertmanager/notify/feishu"
"github.com/prometheus/alertmanager/notify/jira"
"github.com/prometheus/alertmanager/notify/msteams"
"github.com/prometheus/alertmanager/notify/msteamsv2"
Expand Down Expand Up @@ -109,7 +110,9 @@ func BuildReceiverIntegrations(nc config.Receiver, tmpl *template.Template, logg
for i, c := range nc.RocketchatConfigs {
add("rocketchat", i, c, func(l *slog.Logger) (notify.Notifier, error) { return rocketchat.New(c, tmpl, l, httpOpts...) })
}

for i, c := range nc.FeishuConfigs {
add("feishu", i, c, func(l *slog.Logger) (notify.Notifier, error) { return feishu.New(c, tmpl, l, httpOpts...) })
}
if errs.Len() > 0 {
return nil, &errs
}
Expand Down
28 changes: 28 additions & 0 deletions notify/feishu/feishu_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package feishu

import (
"github.com/prometheus/alertmanager/config"
"github.com/prometheus/alertmanager/notify/test"
commoncfg "github.com/prometheus/common/config"
"github.com/prometheus/common/promslog"
"github.com/stretchr/testify/require"
"testing"
)

func TestFeishuInitialAuthentication(t *testing.T) {
_, u, fn := test.GetContextWithCancelingURL()
defer fn()
app_id := "app_id"
app_secret := "app_secret"
_, err := New(
&config.FeishuConfig{
APIURL: &config.URL{URL: u},
HTTPConfig: &commoncfg.HTTPClientConfig{},
APPID: app_id,
APPSecret: config.Secret(app_secret),
},
test.CreateTmpl(t),
promslog.NewNopLogger(),
)
require.NoError(t, err)
}
14 changes: 11 additions & 3 deletions notify/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func RedactURL(err error) error {

// Get sends a GET request to the given URL.
func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
return request(ctx, client, http.MethodGet, url, "", nil)
return request(ctx, client, http.MethodGet, url, "", map[string]string{}, nil)
}

// PostJSON sends a POST request with JSON payload to the given URL.
Expand All @@ -61,11 +61,16 @@ func PostText(ctx context.Context, client *http.Client, url string, body io.Read
return post(ctx, client, url, "text/plain", body)
}

// PostTextAddHeaders sends a POST request with text payload and header to the given URL
func PostTextAddHeaders(ctx context.Context, client *http.Client, url string, headers map[string]string, body io.Reader) (*http.Response, error) {
return request(ctx, client, http.MethodPost, url, "text/plain", headers, body)
}

func post(ctx context.Context, client *http.Client, url, bodyType string, body io.Reader) (*http.Response, error) {
return request(ctx, client, http.MethodPost, url, bodyType, body)
return request(ctx, client, http.MethodPost, url, bodyType, map[string]string{}, body)
}

func request(ctx context.Context, client *http.Client, method, url, bodyType string, body io.Reader) (*http.Response, error) {
func request(ctx context.Context, client *http.Client, method, url, bodyType string, headers map[string]string, body io.Reader) (*http.Response, error) {
req, err := http.NewRequest(method, url, body)
if err != nil {
return nil, err
Expand All @@ -74,6 +79,9 @@ func request(ctx context.Context, client *http.Client, method, url, bodyType str
if bodyType != "" {
req.Header.Set("Content-Type", bodyType)
}
for k, v := range headers {
req.Header.Set(k, v)
}
return client.Do(req.WithContext(ctx))
}

Expand Down
Loading

0 comments on commit fcdd308

Please sign in to comment.