Skip to content

Commit

Permalink
feat: Support slack channel passed as config in notification API (#86)
Browse files Browse the repository at this point in the history
* feat: Support slack channel passed as config in notification API

* fix: use any instead of using interface{} for RecieverSelectors

* fix: refacotor method name error handling

* fix: simplify code

* fix: post notification override

---------

Co-authored-by: Muhammad Abduh <mabdh@users.noreply.github.com>
  • Loading branch information
manishdangi98 and mabdh authored Dec 2, 2024
1 parent e8b3da4 commit cb051b1
Show file tree
Hide file tree
Showing 13 changed files with 458 additions and 70 deletions.
76 changes: 75 additions & 1 deletion core/notification/mocks/receiver_service.go

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

20 changes: 10 additions & 10 deletions core/notification/notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ type Transactor interface {

// Notification is a model of notification
type Notification struct {
ID string `json:"id"`
NamespaceID uint64 `json:"namespace_id"`
Type string `json:"type"`
Data map[string]any `json:"data"`
Labels map[string]string `json:"labels"`
ValidDuration time.Duration `json:"valid_duration"`
Template string `json:"template"`
UniqueKey string `json:"unique_key"`
ReceiverSelectors []map[string]string `json:"receiver_selectors"`
CreatedAt time.Time `json:"created_at"`
ID string `json:"id"`
NamespaceID uint64 `json:"namespace_id"`
Type string `json:"type"`
Data map[string]any `json:"data"`
Labels map[string]string `json:"labels"`
ValidDuration time.Duration `json:"valid_duration"`
Template string `json:"template"`
UniqueKey string `json:"unique_key"`
ReceiverSelectors ReceiverSelectors `json:"receiver_selectors"`
CreatedAt time.Time `json:"created_at"`

// won't be stored in notification table, only to propagate this to notification_subscriber
AlertIDs []int64
Expand Down
2 changes: 1 addition & 1 deletion core/notification/notification_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func TestNotification_Validate(t *testing.T) {
Labels: map[string]string{
"receiver_id": "2",
},
ReceiverSelectors: []map[string]string{
ReceiverSelectors: []map[string]any{
{
"varkey1": "value1",
},
Expand Down
42 changes: 42 additions & 0 deletions core/notification/receiver_selectors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package notification

import (
"github.com/goto/siren/pkg/errors"
)

type ReceiverSelectors []map[string]any

func (rs ReceiverSelectors) parseAndValidate() ([]map[string]string, map[string]any, error) {
// Check if any selector contains a config
var selectorConfig map[string]any
for i := 0; i < len(rs); i++ {
selector := rs[i]
if v, cok := selector["config"]; cok {
if m, ok := v.(map[string]any); ok {
selectorConfig = m
delete(rs[i], "config")
} else {
return nil, nil, errors.ErrInvalid.WithMsgf("config should be in map and follow notification config")
}
break
}
}

if selectorConfig != nil && len(rs) > 1 {
return nil, nil, errors.ErrInvalid.WithMsgf("config override could only be used with one selector")
}

castedSelectors := make([]map[string]string, len(rs))
for i, selector := range rs {
castedSelectors[i] = make(map[string]string)
for k, v := range selector {
if str, ok := v.(string); ok {
castedSelectors[i][k] = str
} else {
return nil, nil, errors.ErrInvalid.WithMsgf("receiver selector value of '%s' should be a string", k)
}
}
}

return castedSelectors, selectorConfig, nil
}
37 changes: 36 additions & 1 deletion core/notification/router_receiver_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@ func (s *RouterReceiverService) PrepareMetaMessages(ctx context.Context, n Notif
return nil, nil, errors.ErrInvalid.WithMsgf("number of receiver selectors should be less than or equal threshold %d", s.deps.Cfg.MaxNumReceiverSelectors)
}

selectors, selectorConfig, err := n.ReceiverSelectors.parseAndValidate()
if err != nil {
return nil, nil, err
}

rcvs, err := s.deps.ReceiverService.List(ctx, receiver.Filter{
MultipleLabels: n.ReceiverSelectors,
MultipleLabels: selectors,
Expanded: true,
})
if err != nil {
Expand All @@ -38,6 +43,24 @@ func (s *RouterReceiverService) PrepareMetaMessages(ctx context.Context, n Notif
return nil, nil, errors.ErrNotFound
}

if selectorConfig != nil && len(rcvs) > 1 {
return nil, nil, errors.ErrInvalid.WithMsgf("config override could only be used to 1 receiver, but got %d receiver", len(rcvs))
} else if selectorConfig != nil && len(rcvs) == 1 {
// config override flow
var rcvView = &subscription.ReceiverView{}
rcvView.FromReceiver(rcvs[0])
rcvView.Configurations = s.mergeReceiverConfig(rcvView.Configurations, selectorConfig)
metaMessages = append(metaMessages, n.MetaMessage(*rcvView))

notificationLogs = append(notificationLogs, log.Notification{
NamespaceID: n.NamespaceID,
NotificationID: n.ID,
ReceiverID: rcvs[0].ID,
AlertIDs: n.AlertIDs,
})
return metaMessages, notificationLogs, nil
}

for _, rcv := range rcvs {
var rcvView = &subscription.ReceiverView{}
rcvView.FromReceiver(rcv)
Expand All @@ -58,3 +81,15 @@ func (s *RouterReceiverService) PrepareMetaMessages(ctx context.Context, n Notif

return metaMessages, notificationLogs, nil
}

func (s *RouterReceiverService) mergeReceiverConfig(receiverConfig, selectorConfig map[string]any) map[string]any {
// override the existing config with the one from API if there is config clash
result := map[string]any{}
for k, v := range receiverConfig {
result[k] = v
}
for k, v := range selectorConfig {
result[k] = v
}
return result
}
Loading

0 comments on commit cb051b1

Please sign in to comment.