mirror of
https://github.com/containrrr/watchtower.git
synced 2025-09-21 21:30:48 +02:00
parent
3bbe1bd109
commit
35490c853d
9 changed files with 375 additions and 295 deletions
|
@ -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)
|
||||
return emailSubject
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
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() {}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue