|
|
|
package notifications
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
t "github.com/containrrr/watchtower/pkg/types"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"io/ioutil"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
msTeamsType = "msteams"
|
|
|
|
)
|
|
|
|
|
|
|
|
type msTeamsTypeNotifier struct {
|
|
|
|
webHookURL string
|
|
|
|
levels []log.Level
|
|
|
|
data bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func newMsTeamsNotifier(cmd *cobra.Command, acceptedLogLevels []log.Level) t.Notifier {
|
|
|
|
|
|
|
|
flags := cmd.PersistentFlags()
|
|
|
|
|
|
|
|
webHookURL, _ := flags.GetString("notification-msteams-hook")
|
|
|
|
if len(webHookURL) <= 0 {
|
|
|
|
log.Fatal("Required argument --notification-msteams-hook(cli) or WATCHTOWER_NOTIFICATION_MSTEAMS_HOOK_URL(env) is empty.")
|
|
|
|
}
|
|
|
|
|
|
|
|
withData, _ := flags.GetBool("notification-msteams-data")
|
|
|
|
n := &msTeamsTypeNotifier{
|
|
|
|
levels: acceptedLogLevels,
|
|
|
|
webHookURL: webHookURL,
|
|
|
|
data: withData,
|
|
|
|
}
|
|
|
|
|
|
|
|
log.AddHook(n)
|
|
|
|
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *msTeamsTypeNotifier) StartNotification() {}
|
|
|
|
|
|
|
|
func (n *msTeamsTypeNotifier) SendNotification() {}
|
|
|
|
|
|
|
|
func (n *msTeamsTypeNotifier) Close() {}
|
|
|
|
|
|
|
|
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"`
|
|
|
|
}
|