cherrypick notification changes from #450 (#745)

pull/450/head
Simon Aronsson 3 years ago committed by GitHub
parent 3bbe1bd109
commit 35490c853d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -34,15 +34,20 @@ var (
scope string
)
var rootCmd = &cobra.Command{
Use: "watchtower",
Short: "Automatically updates running Docker containers",
Long: `
Watchtower automatically updates running Docker containers whenever a new image is released.
More information available at https://github.com/containrrr/watchtower/.
`,
Run: Run,
PreRun: PreRun,
var rootCmd = NewRootCommand()
// NewRootCommand creates the root command for watchtower
func NewRootCommand() *cobra.Command {
return &cobra.Command{
Use: "watchtower",
Short: "Automatically updates running Docker containers",
Long: `
Watchtower automatically updates running Docker containers whenever a new image is released.
More information available at https://github.com/containrrr/watchtower/.
`,
Run: Run,
PreRun: PreRun,
}
}
func init() {

@ -1,29 +1,22 @@
package notifications
import (
"encoding/base64"
"fmt"
"github.com/spf13/cobra"
"net/smtp"
"os"
"strings"
"time"
"github.com/spf13/cobra"
shoutrrrSmtp "github.com/containrrr/shoutrrr/pkg/services/smtp"
t "github.com/containrrr/watchtower/pkg/types"
log "github.com/sirupsen/logrus"
"strconv"
)
const (
emailType = "email"
)
// Implements Notifier, logrus.Hook
// The default logrus email integration would have several issues:
// - It would send one email per log output
// - It would only send errors
// We work around that by holding on to log entries until the update cycle is done.
type emailTypeNotifier struct {
url string
From, To string
Server, User, Password, SubjectTag string
Port int
@ -33,7 +26,12 @@ type emailTypeNotifier struct {
delay time.Duration
}
func newEmailNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.Notifier {
// NewEmailNotifier is a factory method creating a new email notifier instance
func NewEmailNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.ConvertableNotifier {
return newEmailNotifier(c, acceptedLogLevels)
}
func newEmailNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.ConvertableNotifier {
flags := c.PersistentFlags()
from, _ := flags.GetString("notification-email-from")
@ -47,6 +45,7 @@ func newEmailNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.Notifie
subjecttag, _ := flags.GetString("notification-email-subjecttag")
n := &emailTypeNotifier{
entries: []*log.Entry{},
From: from,
To: to,
Server: server,
@ -59,12 +58,33 @@ func newEmailNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.Notifie
SubjectTag: subjecttag,
}
log.AddHook(n)
return n
}
func (e *emailTypeNotifier) buildMessage(entries []*log.Entry) []byte {
func (e *emailTypeNotifier) GetURL() string {
conf := &shoutrrrSmtp.Config{
FromAddress: e.From,
FromName: "Watchtower",
ToAddresses: []string{e.To},
Port: uint16(e.Port),
Host: e.Server,
Subject: e.getSubject(),
Username: e.User,
Password: e.Password,
UseStartTLS: true,
UseHTML: false,
}
if len(e.User) > 0 {
conf.Set("auth", "Plain")
} else {
conf.Set("auth", "None")
}
return conf.GetURL().String()
}
func (e *emailTypeNotifier) getSubject() string {
var emailSubject string
if e.SubjectTag == "" {
@ -75,83 +95,13 @@ func (e *emailTypeNotifier) buildMessage(entries []*log.Entry) []byte {
if hostname, err := os.Hostname(); err == nil {
emailSubject += " on " + hostname
}
body := ""
for _, entry := range entries {
body += entry.Time.Format("2006-01-02 15:04:05") + " (" + entry.Level.String() + "): " + entry.Message + "\r\n"
// We don't use fields in watchtower, so don't bother sending them.
}
t := time.Now()
header := make(map[string]string)
header["From"] = e.From
header["To"] = e.To
header["Subject"] = emailSubject
header["Date"] = t.Format(time.RFC1123Z)
header["MIME-Version"] = "1.0"
header["Content-Type"] = "text/plain; charset=\"utf-8\""
header["Content-Transfer-Encoding"] = "base64"
message := ""
for k, v := range header {
message += fmt.Sprintf("%s: %s\r\n", k, v)
}
encodedBody := base64.StdEncoding.EncodeToString([]byte(body))
//RFC 2045 base64 encoding demands line no longer than 76 characters.
for _, line := range SplitSubN(encodedBody, 76) {
message += "\r\n" + line
}
return []byte(message)
}
func (e *emailTypeNotifier) sendEntries(entries []*log.Entry) {
// Do the sending in a separate goroutine so we don't block the main process.
msg := e.buildMessage(entries)
go func() {
if e.delay > 0 {
time.Sleep(e.delay)
}
var auth smtp.Auth
if e.User != "" {
auth = smtp.PlainAuth("", e.User, e.Password, e.Server)
}
err := SendMail(e.Server+":"+strconv.Itoa(e.Port), e.tlsSkipVerify, auth, e.From, strings.Split(e.To, ","), msg)
if err != nil {
// Use fmt so it doesn't trigger another email.
fmt.Println("Failed to send notification email: ", err)
}
}()
return emailSubject
}
func (e *emailTypeNotifier) StartNotification() {
if e.entries == nil {
e.entries = make([]*log.Entry, 0, 10)
}
}
func (e *emailTypeNotifier) SendNotification() {
if e.entries == nil || len(e.entries) <= 0 {
return
}
e.sendEntries(e.entries)
e.entries = nil
}
func (e *emailTypeNotifier) Levels() []log.Level {
return e.logLevels
}
func (e *emailTypeNotifier) Fire(entry *log.Entry) error {
if e.entries != nil {
e.entries = append(e.entries, entry)
} else {
e.sendEntries([]*log.Entry{entry})
}
return nil
}
// TODO: Delete these once all notifiers have been converted to shoutrrr
func (e *emailTypeNotifier) StartNotification() {}
func (e *emailTypeNotifier) SendNotification() {}
func (e *emailTypeNotifier) Levels() []log.Level { return nil }
func (e *emailTypeNotifier) Fire(entry *log.Entry) error { return nil }
func (e *emailTypeNotifier) Close() {}

@ -1,16 +1,13 @@
package notifications
import (
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
"net/http"
"strings"
shoutrrrGotify "github.com/containrrr/shoutrrr/pkg/services/gotify"
t "github.com/containrrr/watchtower/pkg/types"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
const (
@ -24,94 +21,71 @@ type gotifyTypeNotifier struct {
logLevels []log.Level
}
func newGotifyNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.Notifier {
// NewGotifyNotifier is a factory method creating a new gotify notifier instance
func NewGotifyNotifier(c *cobra.Command, levels []log.Level) t.ConvertableNotifier {
return newGotifyNotifier(c, levels)
}
func newGotifyNotifier(c *cobra.Command, levels []log.Level) t.ConvertableNotifier {
flags := c.PersistentFlags()
gotifyURL, _ := flags.GetString("notification-gotify-url")
if len(gotifyURL) < 1 {
log.Fatal("Required argument --notification-gotify-url(cli) or WATCHTOWER_NOTIFICATION_GOTIFY_URL(env) is empty.")
} else if !(strings.HasPrefix(gotifyURL, "http://") || strings.HasPrefix(gotifyURL, "https://")) {
log.Fatal("Gotify URL must start with \"http://\" or \"https://\"")
} else if strings.HasPrefix(gotifyURL, "http://") {
log.Warn("Using an HTTP url for Gotify is insecure")
url := getGotifyURL(flags)
token := getGotifyToken(flags)
skipVerify, _ := flags.GetBool("notification-gotify-tls-skip-verify")
n := &gotifyTypeNotifier{
gotifyURL: url,
gotifyAppToken: token,
gotifyInsecureSkipVerify: skipVerify,
logLevels: levels,
}
return n
}
func getGotifyToken(flags *pflag.FlagSet) string {
gotifyToken, _ := flags.GetString("notification-gotify-token")
if len(gotifyToken) < 1 {
log.Fatal("Required argument --notification-gotify-token(cli) or WATCHTOWER_NOTIFICATION_GOTIFY_TOKEN(env) is empty.")
}
return gotifyToken
}
gotifyInsecureSkipVerify, _ := flags.GetBool("notification-gotify-tls-skip-verify")
func getGotifyURL(flags *pflag.FlagSet) string {
gotifyURL, _ := flags.GetString("notification-gotify-url")
n := &gotifyTypeNotifier{
gotifyURL: gotifyURL,
gotifyAppToken: gotifyToken,
gotifyInsecureSkipVerify: gotifyInsecureSkipVerify,
logLevels: acceptedLogLevels,
if len(gotifyURL) < 1 {
log.Fatal("Required argument --notification-gotify-url(cli) or WATCHTOWER_NOTIFICATION_GOTIFY_URL(env) is empty.")
} else if !(strings.HasPrefix(gotifyURL, "http://") || strings.HasPrefix(gotifyURL, "https://")) {
log.Fatal("Gotify URL must start with \"http://\" or \"https://\"")
} else if strings.HasPrefix(gotifyURL, "http://") {
log.Warn("Using an HTTP url for Gotify is insecure")
}
log.AddHook(n)
return n
return gotifyURL
}
func (n *gotifyTypeNotifier) StartNotification() {}
func (n *gotifyTypeNotifier) SendNotification() {}
func (n *gotifyTypeNotifier) GetURL() string {
url := n.gotifyURL
func (n *gotifyTypeNotifier) Close() {}
if strings.HasPrefix(url, "https://") {
url = strings.TrimPrefix(url, "https://")
} else {
url = strings.TrimPrefix(url, "http://")
}
func (n *gotifyTypeNotifier) Levels() []log.Level {
return n.logLevels
}
url = strings.TrimSuffix(url, "/")
func (n *gotifyTypeNotifier) getURL() string {
url := n.gotifyURL
if !strings.HasSuffix(url, "/") {
url += "/"
config := &shoutrrrGotify.Config{
Host: url,
Token: n.gotifyAppToken,
}
return url + "message?token=" + n.gotifyAppToken
}
func (n *gotifyTypeNotifier) Fire(entry *log.Entry) error {
go func() {
jsonBody, err := json.Marshal(gotifyMessage{
Message: "(" + entry.Level.String() + "): " + entry.Message,
Title: "Watchtower",
Priority: 0,
})
if err != nil {
fmt.Println("Failed to create JSON body for Gotify notification: ", err)
return
}
// Explicitly define the client so we can set InsecureSkipVerify to the desired value.
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: n.gotifyInsecureSkipVerify,
},
},
}
jsonBodyBuffer := bytes.NewBuffer([]byte(jsonBody))
resp, err := client.Post(n.getURL(), "application/json", jsonBodyBuffer)
if err != nil {
fmt.Println("Failed to send Gotify notification: ", err)
return
}
defer resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
fmt.Printf("Gotify notification returned %d HTTP status code", resp.StatusCode)
}
}()
return nil
return config.GetURL().String()
}
type gotifyMessage struct {
Message string `json:"message"`
Title string `json:"title"`
Priority int `json:"priority"`
}
func (n *gotifyTypeNotifier) StartNotification() {}
func (n *gotifyTypeNotifier) SendNotification() {}
func (n *gotifyTypeNotifier) Close() {}
func (n *gotifyTypeNotifier) Levels() []log.Level { return nil }

@ -1,15 +1,12 @@
package notifications
import (
"bytes"
"encoding/json"
"fmt"
"github.com/spf13/cobra"
"net/http"
"strings"
shoutrrrTeams "github.com/containrrr/shoutrrr/pkg/services/teams"
t "github.com/containrrr/watchtower/pkg/types"
log "github.com/sirupsen/logrus"
"io/ioutil"
"github.com/spf13/cobra"
)
const (
@ -22,7 +19,12 @@ type msTeamsTypeNotifier struct {
data bool
}
func newMsTeamsNotifier(cmd *cobra.Command, acceptedLogLevels []log.Level) t.Notifier {
// NewMsTeamsNotifier is a factory method creating a new teams notifier instance
func NewMsTeamsNotifier(cmd *cobra.Command, acceptedLogLevels []log.Level) t.ConvertableNotifier {
return newMsTeamsNotifier(cmd, acceptedLogLevels)
}
func newMsTeamsNotifier(cmd *cobra.Command, acceptedLogLevels []log.Level) t.ConvertableNotifier {
flags := cmd.PersistentFlags()
@ -38,103 +40,29 @@ func newMsTeamsNotifier(cmd *cobra.Command, acceptedLogLevels []log.Level) t.Not
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,
}
func (n *msTeamsTypeNotifier) GetURL() string {
if n.data && entry.Data != nil && len(entry.Data) > 0 {
section := messageCardSection{
Facts: make([]messageCardSectionFact, len(entry.Data)),
Text: "",
}
baseURL := "https://outlook.office.com/webhook/"
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"`
}
path := strings.Replace(n.webHookURL, baseURL, "", 1)
rawToken := strings.Replace(path, "/IncomingWebhook", "", 1)
token := strings.Split(rawToken, "/")
config := &shoutrrrTeams.Config{
Token: shoutrrrTeams.Token{
A: token[0],
B: token[1],
C: token[2],
},
}
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"`
return config.GetURL().String()
}
type messageCardSectionFact struct {
Name string `json:"name,omitempty"`
Value string `json:"value,omitempty"`
}
func (n *msTeamsTypeNotifier) StartNotification() {}
func (n *msTeamsTypeNotifier) SendNotification() {}
func (n *msTeamsTypeNotifier) Close() {}
func (n *msTeamsTypeNotifier) Levels() []log.Level { return nil }
func (n *msTeamsTypeNotifier) Fire(entry *log.Entry) error { return nil }

@ -31,26 +31,48 @@ func NewNotifier(c *cobra.Command) *Notifier {
if err != nil {
log.WithField("could not read notifications argument", log.Fields{"Error": err}).Fatal()
}
n.types = n.GetNotificationTypes(c, acceptedLogLevels, types)
return n
}
// GetNotificationTypes produces an array of notifiers from a list of types
func (n *Notifier) GetNotificationTypes(cmd *cobra.Command, levels []log.Level, types []string) []ty.Notifier {
output := make([]ty.Notifier, 0)
for _, t := range types {
var tn ty.Notifier
if t == shoutrrrType {
output = append(output, newShoutrrrNotifier(cmd, levels))
continue
}
var legacyNotifier ty.ConvertableNotifier
switch t {
case emailType:
tn = newEmailNotifier(c, acceptedLogLevels)
legacyNotifier = newEmailNotifier(cmd, []log.Level{})
case slackType:
tn = newSlackNotifier(c, acceptedLogLevels)
legacyNotifier = newSlackNotifier(cmd, []log.Level{})
case msTeamsType:
tn = newMsTeamsNotifier(c, acceptedLogLevels)
legacyNotifier = newMsTeamsNotifier(cmd, levels)
case gotifyType:
tn = newGotifyNotifier(c, acceptedLogLevels)
case shoutrrrType:
tn = newShoutrrrNotifier(c, acceptedLogLevels)
legacyNotifier = newGotifyNotifier(cmd, []log.Level{})
default:
log.Fatalf("Unknown notification type %q", t)
}
n.types = append(n.types, tn)
notifier := newShoutrrrNotifierFromURL(
cmd,
legacyNotifier.GetURL(),
levels,
)
output = append(output, notifier)
}
return n
return output
}
// StartNotification starts a log batch. Notifications will be accumulated after this point and only sent when SendNotification() is called.

@ -0,0 +1,163 @@
package notifications_test
import (
"fmt"
"os"
"testing"
"github.com/containrrr/watchtower/cmd"
"github.com/containrrr/watchtower/internal/flags"
"github.com/containrrr/watchtower/pkg/notifications"
"github.com/containrrr/watchtower/pkg/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
func TestActions(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Notifier Suite")
}
var _ = Describe("notifications", func() {
// TODO: Either, we delete this test or we need to pass it valid URLs in the cobra command.
// ---
// When("getting notifiers from a types array", func() {
// It("should return the same amount of notifiers a string entries", func() {
// notifier := &notifications.Notifier{}
// notifiers := notifier.GetNotificationTypes(&cobra.Command{}, []log.Level{}, []string{"slack", "email"})
// Expect(len(notifiers)).To(Equal(2))
// })
// })
Describe("the slack notifier", func() {
When("converting a slack service config into a shoutrrr url", func() {
builderFn := notifications.NewSlackNotifier
It("should return the expected URL", func() {
username := "containrrrbot"
tokenA := "aaa"
tokenB := "bbb"
tokenC := "ccc"
password := fmt.Sprintf("%s-%s-%s", tokenA, tokenB, tokenC)
hookURL := fmt.Sprintf("https://hooks.slack.com/services/%s/%s/%s", tokenA, tokenB, tokenC)
expectedOutput := fmt.Sprintf("slack://%s:%s@%s/%s/%s", username, password, tokenA, tokenB, tokenC)
args := []string{
"--notification-slack-hook-url",
hookURL,
"--notification-slack-identifier",
username,
}
testURL(builderFn, args, expectedOutput)
})
})
})
Describe("the gotify notifier", func() {
When("converting a gotify service config into a shoutrrr url", func() {
builderFn := notifications.NewGotifyNotifier
It("should return the expected URL", func() {
token := "aaa"
host := "shoutrrr.local"
expectedOutput := fmt.Sprintf("gotify://%s/%s", host, token)
args := []string{
"--notification-gotify-url",
fmt.Sprintf("https://%s", host),
"--notification-gotify-token",
token,
}
testURL(builderFn, args, expectedOutput)
})
})
})
Describe("the teams notifier", func() {
When("converting a teams service config into a shoutrrr url", func() {
builderFn := notifications.NewMsTeamsNotifier
It("should return the expected URL", func() {
tokenA := "aaa"
tokenB := "bbb"
tokenC := "ccc"
hookURL := fmt.Sprintf("https://outlook.office.com/webhook/%s/IncomingWebhook/%s/%s", tokenA, tokenB, tokenC)
expectedOutput := fmt.Sprintf("teams://%s:%s@%s", tokenA, tokenB, tokenC)
args := []string{
"--notification-msteams-hook",
hookURL,
}
testURL(builderFn, args, expectedOutput)
})
})
})
Describe("the email notifier", func() {
builderFn := notifications.NewEmailNotifier
When("converting an email service config into a shoutrrr url", func() {
It("should set the from address in the URL", func() {
fromAddress := "lala@example.com"
expectedOutput := buildExpectedURL("", "", "", 25, fromAddress, "", "None")
args := []string{
"--notification-email-from",
fromAddress,
}
testURL(builderFn, args, expectedOutput)
})
It("should return the expected URL", func() {
fromAddress := "sender@example.com"
toAddress := "receiver@example.com"
expectedOutput := buildExpectedURL("", "", "", 25, fromAddress, toAddress, "None")
args := []string{
"--notification-email-from",
fromAddress,
"--notification-email-to",
toAddress,
}
testURL(builderFn, args, expectedOutput)
})
})
})
})
func buildExpectedURL(username string, password string, host string, port int, from string, to string, auth string) string {
hostname, err := os.Hostname()
Expect(err).NotTo(HaveOccurred())
subject := fmt.Sprintf("Watchtower updates on %s", hostname)
var template = "smtp://%s:%s@%s:%d/?fromAddress=%s&fromName=Watchtower&toAddresses=%s&auth=%s&subject=%s&startTls=Yes&useHTML=No"
return fmt.Sprintf(template, username, password, host, port, from, to, auth, subject)
}
type builderFn = func(c *cobra.Command, acceptedLogLevels []log.Level) types.ConvertableNotifier
func testURL(builder builderFn, args []string, expectedURL string) {
command := cmd.NewRootCommand()
flags.RegisterNotificationFlags(command)
command.ParseFlags(args)
notifier := builder(command, []log.Level{})
actualURL := notifier.GetURL()
Expect(actualURL).To(Equal(expectedURL))
}

@ -35,8 +35,17 @@ type shoutrrrTypeNotifier struct {
func newShoutrrrNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.Notifier {
flags := c.PersistentFlags()
urls, _ := flags.GetStringArray("notification-url")
template := getShoutrrrTemplate(c)
return createSender(urls, acceptedLogLevels, template)
}
func newShoutrrrNotifierFromURL(c *cobra.Command, url string, levels []log.Level) t.Notifier {
template := getShoutrrrTemplate(c)
return createSender([]string{url}, levels, template)
}
func createSender(urls []string, levels []log.Level, template *template.Template) t.Notifier {
r, err := shoutrrr.CreateSender(urls...)
if err != nil {
log.Fatalf("Failed to initialize Shoutrrr notifications: %s\n", err.Error())
@ -45,10 +54,10 @@ func newShoutrrrNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.Noti
n := &shoutrrrTypeNotifier{
Urls: urls,
Router: r,
logLevels: acceptedLogLevels,
template: getShoutrrrTemplate(c),
messages: make(chan string, 1),
done: make(chan bool),
logLevels: levels,
template: template,
}
log.AddHook(n)

@ -1,6 +1,9 @@
package notifications
import (
"strings"
shoutrrrSlack "github.com/containrrr/shoutrrr/pkg/services/slack"
t "github.com/containrrr/watchtower/pkg/types"
"github.com/johntdyer/slackrus"
log "github.com/sirupsen/logrus"
@ -15,7 +18,12 @@ type slackTypeNotifier struct {
slackrus.SlackrusHook
}
func newSlackNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.Notifier {
// NewSlackNotifier is a factory function used to generate new instance of the slack notifier type
func NewSlackNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.ConvertableNotifier {
return newSlackNotifier(c, acceptedLogLevels)
}
func newSlackNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.ConvertableNotifier {
flags := c.PersistentFlags()
hookURL, _ := flags.GetString("notification-slack-hook-url")
@ -23,7 +31,6 @@ func newSlackNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.Notifie
channel, _ := flags.GetString("notification-slack-channel")
emoji, _ := flags.GetString("notification-slack-icon-emoji")
iconURL, _ := flags.GetString("notification-slack-icon-url")
n := &slackTypeNotifier{
SlackrusHook: slackrus.SlackrusHook{
HookURL: hookURL,
@ -34,12 +41,27 @@ func newSlackNotifier(c *cobra.Command, acceptedLogLevels []log.Level) t.Notifie
AcceptedLevels: acceptedLogLevels,
},
}
log.AddHook(n)
return n
}
func (s *slackTypeNotifier) StartNotification() {}
func (s *slackTypeNotifier) GetURL() string {
rawTokens := strings.Replace(s.HookURL, "https://hooks.slack.com/services/", "", 1)
tokens := strings.Split(rawTokens, "/")
conf := &shoutrrrSlack.Config{
BotName: s.Username,
Token: shoutrrrSlack.Token{
A: tokens[0],
B: tokens[1],
C: tokens[2],
},
}
return conf.GetURL().String()
}
func (s *slackTypeNotifier) StartNotification() {
}
func (s *slackTypeNotifier) SendNotification() {}

@ -0,0 +1,7 @@
package types
// ConvertableNotifier is a notifier capable of creating a shoutrrr URL
type ConvertableNotifier interface {
Notifier
GetURL() string
}
Loading…
Cancel
Save