A few changes to better align with what I know think it's the best setup in Webex Teams

- Move away from Webhook to APIRUL
- Make the Room ID a require field
- Set Authorization Credentails via Headers

Signed-off-by: gotjosh <josue.abreu@gmail.com>
This commit is contained in:
gotjosh 2022-11-09 14:16:00 +00:00
parent 9e2608ebff
commit ac0dc96127
No known key found for this signature in database
GPG Key ID: A6E1DDE38FF3C74E
6 changed files with 82 additions and 22 deletions

View File

@ -520,8 +520,12 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
if webex.HTTPConfig == nil { if webex.HTTPConfig == nil {
webex.HTTPConfig = c.Global.HTTPConfig webex.HTTPConfig = c.Global.HTTPConfig
} }
if webex.WebhookURL == nil { if webex.APIURL == nil {
return fmt.Errorf("no webex webhook URL provided") if c.Global.WebexAPIURL == nil {
return fmt.Errorf("no global Webex URL set")
}
webex.APIURL = c.Global.WebexAPIURL
} }
} }
@ -624,6 +628,7 @@ func DefaultGlobalConfig() GlobalConfig {
WeChatAPIURL: mustParseURL("https://qyapi.weixin.qq.com/cgi-bin/"), WeChatAPIURL: mustParseURL("https://qyapi.weixin.qq.com/cgi-bin/"),
VictorOpsAPIURL: mustParseURL("https://alert.victorops.com/integrations/generic/20131114/alert/"), VictorOpsAPIURL: mustParseURL("https://alert.victorops.com/integrations/generic/20131114/alert/"),
TelegramAPIUrl: mustParseURL("https://api.telegram.org"), TelegramAPIUrl: mustParseURL("https://api.telegram.org"),
WebexAPIURL: mustParseURL("https://webexapis.com/v1/messages"),
} }
} }
@ -747,6 +752,7 @@ type GlobalConfig struct {
VictorOpsAPIKey Secret `yaml:"victorops_api_key,omitempty" json:"victorops_api_key,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"` 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"` TelegramAPIUrl *URL `yaml:"telegram_api_url,omitempty" json:"telegram_api_url,omitempty"`
WebexAPIURL *URL `yaml:"webex_api_url,omitempty" json:"webex_api_url,omitempty"`
} }
// UnmarshalYAML implements the yaml.Unmarshaler interface for GlobalConfig. // UnmarshalYAML implements the yaml.Unmarshaler interface for GlobalConfig.

View File

@ -867,6 +867,7 @@ func TestEmptyFieldsAndRegex(t *testing.T) {
WeChatAPIURL: mustParseURL("https://qyapi.weixin.qq.com/cgi-bin/"), WeChatAPIURL: mustParseURL("https://qyapi.weixin.qq.com/cgi-bin/"),
VictorOpsAPIURL: mustParseURL("https://alert.victorops.com/integrations/generic/20131114/alert/"), VictorOpsAPIURL: mustParseURL("https://alert.victorops.com/integrations/generic/20131114/alert/"),
TelegramAPIUrl: mustParseURL("https://api.telegram.org"), TelegramAPIUrl: mustParseURL("https://api.telegram.org"),
WebexAPIURL: mustParseURL("https://webexapis.com/v1/messages"),
}, },
Templates: []string{ Templates: []string{

View File

@ -178,17 +178,26 @@ func (nc *NotifierConfig) SendResolved() bool {
type WebexConfig struct { type WebexConfig struct {
NotifierConfig `yaml:",inline" json:",inline"` NotifierConfig `yaml:",inline" json:",inline"`
HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"` HTTPConfig *commoncfg.HTTPClientConfig `yaml:"http_config,omitempty" json:"http_config,omitempty"`
WebhookURL *SecretURL `yaml:"webhook_url,omitempty" json:"webhook_url,omitempty"` APIURL *URL `yaml:"api_url,omitempty" json:"api_url,omitempty"`
Message string `yaml:"message,omitempty" json:"message,omitempty"` Message string `yaml:"message,omitempty" json:"message,omitempty"`
RoomID string `yaml:"room_id,omitempty" json:"room_id,omitempty"` RoomID string `yaml:"room_id" json:"room_id"`
BotToken Secret `yaml:"bot_token" yaml:"bot_token"`
} }
// UnmarshalYAML implements the yaml.Unmarshaler interface. // UnmarshalYAML implements the yaml.Unmarshaler interface.
func (c *WebexConfig) UnmarshalYAML(unmarshal func(interface{}) error) error { func (c *WebexConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
*c = DefaultWebexConfig *c = DefaultWebexConfig
type plain WebexConfig type plain WebexConfig
return unmarshal((*plain)(c)) if err := unmarshal((*plain)(c)); err != nil {
return err
}
if c.RoomID == "" {
return fmt.Errorf("missing room_id on webex_config")
}
return nil
} }
// DiscordConfig configures notifications via Discord. // DiscordConfig configures notifications via Discord.

View File

@ -14,6 +14,7 @@
package config package config
import ( import (
"errors"
"strings" "strings"
"testing" "testing"
@ -866,6 +867,39 @@ func TestWeChatTypeMatcher(t *testing.T) {
} }
} }
func TestWebexConfiguration(t *testing.T) {
tc := []struct {
name string
in string
expected error
}{
{
name: "with no room_id - it fails",
in: `
bot_token: xyz123
`,
expected: errors.New("missing room_id on webex_config"),
},
{
name: "with room_id and bot_token present - it succeeds",
in: `
room_id: 2
bot_token: xyz123
`,
},
}
for _, tt := range tc {
t.Run(tt.name, func(t *testing.T) {
var cfg WebexConfig
err := yaml.UnmarshalStrict([]byte(tt.in), &cfg)
require.Equal(t, tt.expected, err)
})
}
}
func newBoolPointer(b bool) *bool { func newBoolPointer(b bool) *bool {
return &b return &b
} }

View File

@ -35,28 +35,35 @@ const (
) )
type Notifier struct { type Notifier struct {
conf *config.WebexConfig conf *config.WebexConfig
tmpl *template.Template tmpl *template.Template
logger log.Logger logger log.Logger
client *http.Client client *http.Client
retrier *notify.Retrier retrier *notify.Retrier
webhookURL *config.SecretURL APIURL *config.URL
} }
// New returns a new Webex notifier. // New returns a new Webex notifier.
func New(c *config.WebexConfig, t *template.Template, l log.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) { func New(c *config.WebexConfig, t *template.Template, l log.Logger, httpOpts ...commoncfg.HTTPClientOption) (*Notifier, error) {
if c.HTTPConfig.Authorization == nil && c.HTTPConfig.BearerToken == "" {
c.HTTPConfig.Authorization = &commoncfg.Authorization{
Type: "Bearer",
Credentials: commoncfg.Secret(c.BotToken),
}
}
client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "webex", httpOpts...) client, err := commoncfg.NewClientFromConfig(*c.HTTPConfig, "webex", httpOpts...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
n := &Notifier{ n := &Notifier{
conf: c, conf: c,
tmpl: t, tmpl: t,
logger: l, logger: l,
client: client, client: client,
retrier: &notify.Retrier{}, retrier: &notify.Retrier{},
webhookURL: c.WebhookURL, APIURL: c.APIURL,
} }
return n, nil return n, nil
@ -102,7 +109,7 @@ func (n *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error)
return false, err return false, err
} }
resp, err := notify.PostJSON(ctx, n.client, n.webhookURL.String(), &payload) resp, err := notify.PostJSON(ctx, n.client, n.APIURL.String(), &payload)
if err != nil { if err != nil {
return true, notify.RedactURL(err) return true, notify.RedactURL(err)
} }

View File

@ -41,7 +41,7 @@ func TestWebexRetry(t *testing.T) {
notifier, err := New( notifier, err := New(
&config.WebexConfig{ &config.WebexConfig{
HTTPConfig: &commoncfg.HTTPClientConfig{}, HTTPConfig: &commoncfg.HTTPClientConfig{},
WebhookURL: &config.SecretURL{URL: testWebhookURL}, APIURL: &config.URL{URL: testWebhookURL},
}, },
test.CreateTmpl(t), test.CreateTmpl(t),
log.NewNopLogger(), log.NewNopLogger(),
@ -85,15 +85,18 @@ func TestWebexTemplating(t *testing.T) {
for _, tt := range tc { for _, tt := range tc {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
var out []byte var out []byte
var header http.Header
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var err error var err error
out, err = io.ReadAll(r.Body) out, err = io.ReadAll(r.Body)
header = r.Header.Clone()
require.NoError(t, err) require.NoError(t, err)
})) }))
defer srv.Close() defer srv.Close()
u, _ := url.Parse(srv.URL) u, _ := url.Parse(srv.URL)
tt.cfg.WebhookURL = &config.SecretURL{URL: u} tt.cfg.APIURL = &config.URL{URL: u}
tt.cfg.BotToken = "xxxyyyzz"
tt.cfg.HTTPConfig = &commoncfg.HTTPClientConfig{} tt.cfg.HTTPConfig = &commoncfg.HTTPClientConfig{}
notifierWebex, err := New(tt.cfg, test.CreateTmpl(t), log.NewNopLogger()) notifierWebex, err := New(tt.cfg, test.CreateTmpl(t), log.NewNopLogger())
require.NoError(t, err) require.NoError(t, err)
@ -127,7 +130,7 @@ func TestWebexTemplating(t *testing.T) {
if tt.errMsg == "" { if tt.errMsg == "" {
require.NoError(t, err) require.NoError(t, err)
fmt.Println(string(out)) require.Equal(t, "sss", header.Get("Authorization"))
require.JSONEq(t, tt.expJSON, string(out)) require.JSONEq(t, tt.expJSON, string(out))
} else { } else {
require.Error(t, err) require.Error(t, err)