Notifications via MSTeams (#174)

* Notifications via MSTeams
pull/178/head
Maxim 6 years ago committed by stffabi
parent 88a7a084a9
commit aa1ce68e3a

@ -254,3 +254,23 @@ docker run -d \
-e WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=watchtower-server-1 \
v2tec/watchtower
```
### Notifications via MSTeams incoming webhook
To receive notifications in MSTeams channel, add `msteams` to the `--notifications` option or the `WATCHTOWER_NOTIFICATIONS` environment variable.
Additionally, you should set the MSTeams webhook url using the `--notification-msteams-hook` option or the `WATCHTOWER_NOTIFICATION_MSTEAMS_HOOK_URL` environment variable.
MSTeams notifier could send keys/values filled by ```log.WithField``` or ```log.WithFields``` as MSTeams message facts. To enable this feature add `--notification-msteams-data` flag or set `WATCHTOWER_NOTIFICATION_MSTEAMS_USE_LOG_DATA=true` environment variable.
Example:
```bash
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WATCHTOWER_NOTIFICATIONS=msteams \
-e WATCHTOWER_NOTIFICATION_MSTEAMS_HOOK_URL="https://outlook.office.com/webhook/xxxxxxxx@xxxxxxx/IncomingWebhook/yyyyyyyy/zzzzzzzzzz" \
-e WATCHTOWER_NOTIFICATION_MSTEAMS_USE_LOG_DATA=true \
v2tec/watchtower
```

@ -101,7 +101,7 @@ func main() {
cli.StringSliceFlag{
Name: "notifications",
Value: &cli.StringSlice{},
Usage: "notification types to send (valid: email, slack)",
Usage: "notification types to send (valid: email, slack, msteams)",
EnvVar: "WATCHTOWER_NOTIFICATIONS",
},
cli.StringFlag{
@ -161,6 +161,16 @@ func main() {
EnvVar: "WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER",
Value: "watchtower",
},
cli.StringFlag{
Name: "notification-msteams-hook",
Usage: "The MSTeams WebHook URL to send notifications to",
EnvVar: "WATCHTOWER_NOTIFICATION_MSTEAMS_HOOK_URL",
},
cli.BoolFlag{
Name: "notification-msteams-data",
Usage: "The MSTeams notifier will try to extract log entry fields as MSTeams message facts",
EnvVar: "WATCHTOWER_NOTIFICATION_MSTEAMS_USE_LOG_DATA",
},
}
if err := app.Run(os.Args); err != nil {

@ -0,0 +1,134 @@
package notifications
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli"
"io/ioutil"
)
const (
msTeamsType = "msteams"
)
type msTeamsTypeNotifier struct {
webHookURL string
levels []log.Level
data bool
}
func newMsTeamsNotifier(c *cli.Context, acceptedLogLevels []log.Level) typeNotifier {
webHookURL := c.GlobalString("notification-msteams-hook")
if len(webHookURL) <= 0 {
log.Fatal("Required argument --notification-msteams-hook(cli) or WATCHTOWER_NOTIFICATION_MSTEAMS_HOOK_URL(env) is empty.")
}
n := &msTeamsTypeNotifier{
levels: acceptedLogLevels,
webHookURL: webHookURL,
data: c.GlobalBool("notification-msteams-data"),
}
log.AddHook(n)
return n
}
func (n *msTeamsTypeNotifier) StartNotification() {}
func (n *msTeamsTypeNotifier) SendNotification() {}
func (n *msTeamsTypeNotifier) Levels() []log.Level {
return n.levels
}
func (n *msTeamsTypeNotifier) Fire(entry *log.Entry) error {
message := "(" + entry.Level.String() + "): " + entry.Message
go func() {
webHookBody := messageCard{
CardType: "MessageCard",
Context: "http://schema.org/extensions",
Markdown: true,
Text: message,
}
if n.data && entry.Data != nil && len(entry.Data) > 0 {
section := messageCardSection{
Facts: make([]messageCardSectionFact, len(entry.Data)),
Text: "",
}
index := 0
for k, v := range entry.Data {
section.Facts[index] = messageCardSectionFact{
Name: k,
Value: fmt.Sprint(v),
}
index++
}
webHookBody.Sections = []messageCardSection{section}
}
jsonBody, err := json.Marshal(webHookBody)
if err != nil {
fmt.Println("Failed to build JSON body for MSTeams notificattion: ", err)
return
}
resp, err := http.Post(n.webHookURL, "application/json", bytes.NewBuffer([]byte(jsonBody)))
if err != nil {
fmt.Println("Failed to send MSTeams notificattion: ", err)
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode > 299 {
fmt.Println("Failed to send MSTeams notificattion. HTTP RESPONSE STATUS: ", resp.StatusCode)
if resp.Body != nil {
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err == nil {
bodyString := string(bodyBytes)
fmt.Println(bodyString)
}
}
}
}()
return nil
}
type messageCard struct {
CardType string `json:"@type"`
Context string `json:"@context"`
CorrelationID string `json:"correlationId,omitempty"`
ThemeColor string `json:"themeColor,omitempty"`
Summary string `json:"summary,omitempty"`
Title string `json:"title,omitempty"`
Text string `json:"text,omitempty"`
Markdown bool `json:"markdown,bool"`
Sections []messageCardSection `json:"sections,omitempty"`
}
type messageCardSection struct {
Title string `json:"title,omitempty"`
Text string `json:"text,omitempty"`
ActivityTitle string `json:"activityTitle,omitempty"`
ActivitySubtitle string `json:"activitySubtitle,omitempty"`
ActivityImage string `json:"activityImage,omitempty"`
ActivityText string `json:"activityText,omitempty"`
HeroImage string `json:"heroImage,omitempty"`
Facts []messageCardSectionFact `json:"facts,omitempty"`
}
type messageCardSectionFact struct {
Name string `json:"name,omitempty"`
Value string `json:"value,omitempty"`
}

@ -36,6 +36,8 @@ func NewNotifier(c *cli.Context) *Notifier {
tn = newEmailNotifier(c, acceptedLogLevels)
case slackType:
tn = newSlackNotifier(c, acceptedLogLevels)
case msTeamsType:
tn = newMsTeamsNotifier(c, acceptedLogLevels)
default:
log.Fatalf("Unknown notification type %q", t)
}

Loading…
Cancel
Save