Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(notification/teams): add teams notification - server side #19744

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions notification/endpoint/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ const (
PagerDutyType = "pagerduty"
HTTPType = "http"
TelegramType = "telegram"
TeamsType = "teams"
)

var typeToEndpoint = map[string]func() influxdb.NotificationEndpoint{
SlackType: func() influxdb.NotificationEndpoint { return &Slack{} },
PagerDutyType: func() influxdb.NotificationEndpoint { return &PagerDuty{} },
HTTPType: func() influxdb.NotificationEndpoint { return &HTTP{} },
TelegramType: func() influxdb.NotificationEndpoint { return &Telegram{} },
TeamsType: func() influxdb.NotificationEndpoint { return &Teams{} },
}

// UnmarshalJSON will convert the bytes to notification endpoint.
Expand Down
113 changes: 113 additions & 0 deletions notification/endpoint/endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,24 @@ func TestValidEndpoint(t *testing.T) {
},
err: nil,
},
{
name: "empty teams url",
src: &endpoint.Teams{
Base: goodBase,
},
err: &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "teams: empty URL",
},
},
{
name: "empty teams SecretURLSuffix",
src: &endpoint.Teams{
Base: goodBase,
URL: "http://localhost",
},
err: nil,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
Expand Down Expand Up @@ -305,6 +323,39 @@ func TestJSON(t *testing.T) {
Token: influxdb.SecretField{Key: "token-key-1"},
},
},
{
name: "teams with secretURLSuffix",
src: &endpoint.Teams{
Base: endpoint.Base{
ID: influxTesting.MustIDBase16Ptr(id1),
Name: "name1",
OrgID: influxTesting.MustIDBase16Ptr(id3),
Status: influxdb.Active,
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
URL: "https://outlook.office.com/webhook/",
SecretURLSuffix: influxdb.SecretField{Key: "token-key-1"},
},
},
{
name: "teams without secretURLSuffix",
src: &endpoint.Teams{
Base: endpoint.Base{
ID: influxTesting.MustIDBase16Ptr(id1),
Name: "name1",
OrgID: influxTesting.MustIDBase16Ptr(id3),
Status: influxdb.Active,
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
URL: "https://outlook.office.com/webhook/0acbc9c2-c262-11ea-b3de-0242ac130004",
},
},
}
for _, c := range cases {
b, err := json.Marshal(c.src)
Expand Down Expand Up @@ -478,6 +529,42 @@ func TestBackFill(t *testing.T) {
},
},
},
{
name: "simple Teams",
src: &endpoint.Teams{
Base: endpoint.Base{
ID: influxTesting.MustIDBase16Ptr(id1),
Name: "name1",
OrgID: influxTesting.MustIDBase16Ptr(id3),
Status: influxdb.Active,
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
URL: "https://outlook.office.com/webhook/",
SecretURLSuffix: influxdb.SecretField{
Value: strPtr("token-value"),
},
},
target: &endpoint.Teams{
Base: endpoint.Base{
ID: influxTesting.MustIDBase16Ptr(id1),
Name: "name1",
OrgID: influxTesting.MustIDBase16Ptr(id3),
Status: influxdb.Active,
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
URL: "https://outlook.office.com/webhook/",
SecretURLSuffix: influxdb.SecretField{
Key: id1 + "-token",
Value: strPtr("token-value"),
},
},
},
}
for _, c := range cases {
c.src.BackfillSecretKeys()
Expand Down Expand Up @@ -605,6 +692,32 @@ func TestSecretFields(t *testing.T) {
},
},
},
{
name: "simple Teams",
src: &endpoint.Teams{
Base: endpoint.Base{
ID: influxTesting.MustIDBase16Ptr(id1),
Name: "name1",
OrgID: influxTesting.MustIDBase16Ptr(id3),
Status: influxdb.Active,
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
URL: "https://outlook.office.com/webhook/",
SecretURLSuffix: influxdb.SecretField{
Key: id1 + "-token",
Value: strPtr("token-value"),
},
},
secrets: []influxdb.SecretField{
{
Key: id1 + "-token",
Value: strPtr("token-value"),
},
},
},
}
for _, c := range cases {
secretFields := c.src.SecretFields()
Expand Down
72 changes: 72 additions & 0 deletions notification/endpoint/teams.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package endpoint

import (
"encoding/json"

"github.com/influxdata/influxdb/v2"
)

var _ influxdb.NotificationEndpoint = &Teams{}

const teamsSecretSuffix = "-token"

// Teams is the notification endpoint config of Microdoft teams.
type Teams struct {
Base
// URL is the teams incoming webhook URL, see https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using#setting-up-a-custom-incoming-webhook ,
// for example: https://outlook.office.com/webhook/0acbc9c2-c262-11ea-b3de-0242ac130004
URL string `json:"url"`
// SecretURLSuffix is an optional secret suffix that is added to URL ,
// for example: 0acbc9c2-c262-11ea-b3de-0242ac130004 is the secret part that is added to https://outlook.office.com/webhook/
SecretURLSuffix influxdb.SecretField `json:"secretURLSuffix"`
}

// BackfillSecretKeys fill back the secret field key during the unmarshalling
// if value of that secret field is not nil.
func (s *Teams) BackfillSecretKeys() {
if s.SecretURLSuffix.Key == "" && s.SecretURLSuffix.Value != nil {
s.SecretURLSuffix.Key = s.idStr() + teamsSecretSuffix
}
}

// SecretFields return available secret fields.
func (s Teams) SecretFields() []influxdb.SecretField {
arr := []influxdb.SecretField{}
if s.SecretURLSuffix.Key != "" {
arr = append(arr, s.SecretURLSuffix)
}
return arr
}

// Valid returns error if some configuration is invalid
func (s Teams) Valid() error {
if err := s.Base.valid(); err != nil {
return err
}
if s.URL == "" {
return &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "teams: empty URL",
}
}
return nil
}

type teamsAlias Teams

// MarshalJSON implement json.Marshaler interface.
func (s Teams) MarshalJSON() ([]byte, error) {
return json.Marshal(
struct {
teamsAlias
Type string `json:"type"`
}{
teamsAlias: teamsAlias(s),
Type: s.Type(),
})
}

// Type returns the type.
func (s Teams) Type() string {
return TeamsType
}
1 change: 1 addition & 0 deletions notification/rule/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var typeToRule = map[string](func() influxdb.NotificationRule){
"pagerduty": func() influxdb.NotificationRule { return &PagerDuty{} },
"http": func() influxdb.NotificationRule { return &HTTP{} },
"telegram": func() influxdb.NotificationRule { return &Telegram{} },
"teams": func() influxdb.NotificationRule { return &Teams{} },
}

// UnmarshalJSON will convert
Expand Down
36 changes: 36 additions & 0 deletions notification/rule/rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,42 @@ func TestJSON(t *testing.T) {
MessageTemplate: "blah",
},
},
{
name: "simple teams",
src: &rule.Teams{
Base: rule.Base{
ID: influxTesting.MustIDBase16(id1),
OwnerID: influxTesting.MustIDBase16(id2),
Name: "name1",
OrgID: influxTesting.MustIDBase16(id3),
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: mustDuration("1h"),
TagRules: []notification.TagRule{
{
Tag: influxdb.Tag{
Key: "k1",
Value: "v1",
},
Operator: influxdb.NotEqual,
},
{
Tag: influxdb.Tag{
Key: "k2",
Value: "v2",
},
Operator: influxdb.RegexEqual,
},
},
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
Title: "my title",
MessageTemplate: "msg1",
},
},
}
for _, c := range cases {
b, err := json.Marshal(c.src)
Expand Down
Loading