mirror of
https://github.com/containrrr/watchtower.git
synced 2025-12-14 06:06:38 +01:00
parent
88a7a084a9
commit
aa1ce68e3a
4 changed files with 167 additions and 1 deletions
20
README.md
20
README.md
|
|
@ -254,3 +254,23 @@ docker run -d \
|
||||||
-e WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=watchtower-server-1 \
|
-e WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=watchtower-server-1 \
|
||||||
v2tec/watchtower
|
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
|
||||||
|
```
|
||||||
|
|
|
||||||
12
main.go
12
main.go
|
|
@ -101,7 +101,7 @@ func main() {
|
||||||
cli.StringSliceFlag{
|
cli.StringSliceFlag{
|
||||||
Name: "notifications",
|
Name: "notifications",
|
||||||
Value: &cli.StringSlice{},
|
Value: &cli.StringSlice{},
|
||||||
Usage: "notification types to send (valid: email, slack)",
|
Usage: "notification types to send (valid: email, slack, msteams)",
|
||||||
EnvVar: "WATCHTOWER_NOTIFICATIONS",
|
EnvVar: "WATCHTOWER_NOTIFICATIONS",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
|
|
@ -161,6 +161,16 @@ func main() {
|
||||||
EnvVar: "WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER",
|
EnvVar: "WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER",
|
||||||
Value: "watchtower",
|
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 {
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
|
|
||||||
134
notifications/msteams.go
Normal file
134
notifications/msteams.go
Normal file
|
|
@ -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)
|
tn = newEmailNotifier(c, acceptedLogLevels)
|
||||||
case slackType:
|
case slackType:
|
||||||
tn = newSlackNotifier(c, acceptedLogLevels)
|
tn = newSlackNotifier(c, acceptedLogLevels)
|
||||||
|
case msTeamsType:
|
||||||
|
tn = newMsTeamsNotifier(c, acceptedLogLevels)
|
||||||
default:
|
default:
|
||||||
log.Fatalf("Unknown notification type %q", t)
|
log.Fatalf("Unknown notification type %q", t)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue