Skip to content

Commit

Permalink
Add new dispatcher Slack (dsrvlabs#538)
Browse files Browse the repository at this point in the history
  • Loading branch information
xellos00 authored Dec 28, 2023
1 parent 636d8ee commit 4aab81a
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 1 deletion.
2 changes: 2 additions & 0 deletions cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ func createInitCommand(initializer tp.Initializer) *cobra.Command {
secret: "Put your Discord Webhook"
- channel: "pagerduty"
secret: "Put your PagerDuty's Integration Key (Events API v2)"
- channel: "slack"
secret: "Put Your Slack Webhook url"
- channel: "telegram"
secret: "Put Your Bot's Token"
chat_id: "Put Your Chat's chat_id"
Expand Down
9 changes: 9 additions & 0 deletions manager/dispatcher/dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ func GetDispatchers(cfg config.NotificationInfo) []Dispatcher {
reminderSchedule: chanInfo.ReminderSchedule,
entry: sync.Map{},
})
case strings.EqualFold(channel, string(tp.Slack)):
dispatcherSingletons = append(dispatcherSingletons, &slack{
host: cfg.HostName,
channel: tp.Slack,
secret: chanInfo.Secret,
reminderCron: cron.New(cron.WithLocation(time.UTC)),
reminderSchedule: chanInfo.ReminderSchedule,
entry: sync.Map{},
})
case strings.EqualFold(channel, string(tp.PagerDuty)):
dispatcherSingletons = append(dispatcherSingletons, &pagerduty{
host: cfg.HostName,
Expand Down
126 changes: 126 additions & 0 deletions manager/dispatcher/slack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package dispatcher

import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"sync"

pb "github.com/dsrvlabs/vatz-proto/plugin/v1"
tp "github.com/dsrvlabs/vatz/manager/types"
"github.com/robfig/cron/v3"
"github.com/rs/zerolog/log"
)

// slack: This is a sample code
// that helps to multi methods for notification.
type slack struct {
host string
channel tp.Channel
secret string
reminderSchedule []string
reminderCron *cron.Cron
entry sync.Map
}

type SlackRequestBody struct {
Text string `json:"text"`
}

func (t *slack) SetDispatcher(firstRunMsg bool, preStat tp.StateFlag, notifyInfo tp.NotifyInfo) error {
reqToNotify, reminderState, deliverMessage := messageHandler(firstRunMsg, preStat, notifyInfo)
pUnique := deliverMessage.Options["pUnique"].(string)

if reqToNotify {
err := t.SendNotification(deliverMessage)
if err != nil {
log.Error().Str("module", "dispatcher").Msgf("Channel(Slack): Send notification error: %s", err)
return err
}

}

if reminderState == tp.ON {
newEntries := []cron.EntryID{}
/*
In case of reminder has to keep but stateFlag has changed,
e.g.) CRITICAL -> WARNING
e.g.) ERROR -> INFO -> ERROR
*/
if entries, ok := t.entry.Load(pUnique); ok {
for _, entry := range entries.([]cron.EntryID) {
t.reminderCron.Remove(entry)
}
t.reminderCron.Stop()
}
for _, schedule := range t.reminderSchedule {
id, _ := t.reminderCron.AddFunc(schedule, func() {
err := t.SendNotification(deliverMessage)
if err != nil {
log.Error().Str("module", "dispatcher").Msgf("Channel(Slack): Send notification error: %s", err)
}
})
newEntries = append(newEntries, id)
}
t.entry.Store(pUnique, newEntries)
t.reminderCron.Start()
} else if reminderState == tp.OFF {
entries, _ := t.entry.Load(pUnique)
if _, ok := entries.([]cron.EntryID); ok {
for _, entity := range entries.([]cron.EntryID) {
t.reminderCron.Remove(entity)
}
t.reminderCron.Stop()
}
}
return nil
}

func (t *slack) SendNotification(msg tp.ReqMsg) error {
var (
err error
emoji = emojiER
)

if msg.State == pb.STATE_SUCCESS {
switch {
case msg.Severity == pb.SEVERITY_CRITICAL:
emoji = emojiDoubleEX
case msg.Severity == pb.SEVERITY_WARNING:
emoji = emojiSingleEx
case msg.Severity == pb.SEVERITY_INFO:
emoji = emojiCheck
}
}
sendingText := fmt.Sprintf(`
%s *%s* %s
>
Host: *%s*
Plugin Name: _%s_
%s`, emoji, msg.Severity.String(), emoji, t.host, msg.ResourceType, msg.Msg)
slackBody, _ := json.Marshal(SlackRequestBody{Text: sendingText})
req, err := http.NewRequest(http.MethodPost, t.secret, bytes.NewBuffer(slackBody))
if err != nil {
return err
}

req.Header.Add("Content-Type", "application/json")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}

buf := new(bytes.Buffer)
_, err = buf.ReadFrom(resp.Body)
if err != nil {
return err
}
if buf.String() != "ok" {
return fmt.Errorf("non-ok response returned from Slack")
}

return nil
}
2 changes: 1 addition & 1 deletion manager/dispatcher/telegram.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (t *telegram) SendNotification(msg tp.ReqMsg) error {
url := fmt.Sprintf("%s/sendMessage", getURL(t.secret))
sendingText := fmt.Sprintf(`
%s<strong>%s</strong>%s
<strong>(%s)</strong>
Host: <strong>%s</strong>
Plugin Name: <em>%s</em>
%s`, emoji, msg.Severity.String(), emoji, t.host, msg.ResourceType, msg.Msg)

Expand Down
1 change: 1 addition & 0 deletions manager/types/dispatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ const (
Discord Channel = "DISCORD"
Telegram Channel = "TELEGRAM"
PagerDuty Channel = "PAGERDUTY"
Slack Channel = "SLACK"
)

// Reminder is for reminnig alert.
Expand Down

0 comments on commit 4aab81a

Please sign in to comment.