mirror of
https://github.com/containrrr/watchtower.git
synced 2025-12-16 15:10:12 +01:00
Add discord notification service. Close #143
This commit is contained in:
parent
2cfbebb0e9
commit
fd106e7b00
4 changed files with 129 additions and 16 deletions
10
README.md
10
README.md
|
|
@ -189,7 +189,9 @@ Watchtower can send notifications when containers are updated. Notifications are
|
||||||
The types of notifications to send are passed via the comma-separated option `--notifications` (or corresponding environment variable `WATCHTOWER_NOTIFICATIONS`), which has the following valid values:
|
The types of notifications to send are passed via the comma-separated option `--notifications` (or corresponding environment variable `WATCHTOWER_NOTIFICATIONS`), which has the following valid values:
|
||||||
|
|
||||||
* `email` to send notifications via e-mail
|
* `email` to send notifications via e-mail
|
||||||
|
* `discord` to send notifications into Discord channel
|
||||||
|
|
||||||
|
### Email
|
||||||
To receive notifications by email, the following command-line options, or their corresponding environment variables, can be set:
|
To receive notifications by email, the following command-line options, or their corresponding environment variables, can be set:
|
||||||
|
|
||||||
* `--notification-email-from` (env. `WATCHTOWER_NOTIFICATION_EMAIL_FROM`): The e-mail address from which notifications will be sent.
|
* `--notification-email-from` (env. `WATCHTOWER_NOTIFICATION_EMAIL_FROM`): The e-mail address from which notifications will be sent.
|
||||||
|
|
@ -214,3 +216,11 @@ docker run -d \
|
||||||
v2tec/watchtower
|
v2tec/watchtower
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Discord
|
||||||
|
To send notifications into Discord channel, the following command-line options, or their corresponding environment variables, can be set:
|
||||||
|
|
||||||
|
* `--notification-discord-webhook` (env. `WATCHTOWER_NOTIFICATION_DISCORD_WEBHOOK`): Webhook URL configured in Discord.
|
||||||
|
|
||||||
|
[Checkout how to add webhook for channel](https://support.discordapp.com/hc/en-us/articles/228383668)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
37
main.go
37
main.go
|
|
@ -91,42 +91,47 @@ func main() {
|
||||||
Usage: "enable debug mode with verbose logging",
|
Usage: "enable debug mode with verbose logging",
|
||||||
},
|
},
|
||||||
cli.StringSliceFlag{
|
cli.StringSliceFlag{
|
||||||
Name: "notifications",
|
Name: "notifications",
|
||||||
Value: &cli.StringSlice{},
|
Value: &cli.StringSlice{},
|
||||||
Usage: "notification types to send (valid: email)",
|
Usage: "notification types to send (valid: email, discord)",
|
||||||
EnvVar: "WATCHTOWER_NOTIFICATIONS",
|
EnvVar: "WATCHTOWER_NOTIFICATIONS",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "notification-email-from",
|
Name: "notification-email-from",
|
||||||
Usage: "Address to send notification e-mails from",
|
Usage: "Address to send notification e-mails from",
|
||||||
EnvVar: "WATCHTOWER_NOTIFICATION_EMAIL_FROM",
|
EnvVar: "WATCHTOWER_NOTIFICATION_EMAIL_FROM",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "notification-email-to",
|
Name: "notification-email-to",
|
||||||
Usage: "Address to send notification e-mails to",
|
Usage: "Address to send notification e-mails to",
|
||||||
EnvVar: "WATCHTOWER_NOTIFICATION_EMAIL_TO",
|
EnvVar: "WATCHTOWER_NOTIFICATION_EMAIL_TO",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "notification-email-server",
|
Name: "notification-email-server",
|
||||||
Usage: "SMTP server to send notification e-mails through",
|
Usage: "SMTP server to send notification e-mails through",
|
||||||
EnvVar: "WATCHTOWER_NOTIFICATION_EMAIL_SERVER",
|
EnvVar: "WATCHTOWER_NOTIFICATION_EMAIL_SERVER",
|
||||||
},
|
},
|
||||||
cli.IntFlag{
|
cli.IntFlag{
|
||||||
Name: "notification-email-server-port",
|
Name: "notification-email-server-port",
|
||||||
Usage: "SMTP server port to send notification e-mails through",
|
Usage: "SMTP server port to send notification e-mails through",
|
||||||
Value: 25,
|
Value: 25,
|
||||||
EnvVar: "WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT",
|
EnvVar: "WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "notification-email-server-user",
|
Name: "notification-email-server-user",
|
||||||
Usage: "SMTP server user for sending notifications",
|
Usage: "SMTP server user for sending notifications",
|
||||||
EnvVar: "WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER",
|
EnvVar: "WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER",
|
||||||
},
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "notification-email-server-password",
|
Name: "notification-email-server-password",
|
||||||
Usage: "SMTP server password for sending notifications",
|
Usage: "SMTP server password for sending notifications",
|
||||||
EnvVar: "WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD",
|
EnvVar: "WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD",
|
||||||
},
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "notification-discord-webhook",
|
||||||
|
Usage: "Discord webhook url for sending notifications",
|
||||||
|
EnvVar: "WATCHTOWER_NOTIFICATION_DISCORD_WEBHOOK",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
|
@ -180,7 +185,7 @@ func start(c *cli.Context) error {
|
||||||
scheduleSpec,
|
scheduleSpec,
|
||||||
func() {
|
func() {
|
||||||
select {
|
select {
|
||||||
case v := <- tryLockSem:
|
case v := <-tryLockSem:
|
||||||
defer func() { tryLockSem <- v }()
|
defer func() { tryLockSem <- v }()
|
||||||
notifier.StartNotification()
|
notifier.StartNotification()
|
||||||
if err := actions.Update(client, names, cleanup, noRestart); err != nil {
|
if err := actions.Update(client, names, cleanup, noRestart); err != nil {
|
||||||
|
|
|
||||||
96
notifications/discord.go
Normal file
96
notifications/discord.go
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
package notifications
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
discordType = "discord"
|
||||||
|
)
|
||||||
|
|
||||||
|
type discordTypeNotifier struct {
|
||||||
|
WebhookURL string
|
||||||
|
entries []*log.Entry
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDiscordNotifier(c *cli.Context) typeNotifier {
|
||||||
|
n := &discordTypeNotifier{
|
||||||
|
WebhookURL: c.GlobalString("notification-discord-webhook"),
|
||||||
|
}
|
||||||
|
|
||||||
|
log.AddHook(n)
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *discordTypeNotifier) sendEntries(entries []*log.Entry) {
|
||||||
|
// Do the sending in a separate goroutine so we don't block the main process.
|
||||||
|
message := ""
|
||||||
|
for _, entry := range entries {
|
||||||
|
message += entry.Time.Format("2006-01-02 15:04:05") + " (" + entry.Level.String() + "): " + entry.Message + "\r\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
webhookBody := discordWebhookBody{Content: message}
|
||||||
|
jsonBody, err := json.Marshal(webhookBody)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to build JSON body for Discord notificattion: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.Post(n.WebhookURL, "application/json", bytes.NewBuffer([]byte(jsonBody)))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to send Discord notificattion: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
||||||
|
fmt.Println("Failed to send Discord notificattion. HTTP RESPONSE STATUS: ", resp.StatusCode)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *discordTypeNotifier) StartNotification() {
|
||||||
|
if n.entries == nil {
|
||||||
|
n.entries = make([]*log.Entry, 0, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *discordTypeNotifier) SendNotification() {
|
||||||
|
if n.entries != nil && len(n.entries) != 0 {
|
||||||
|
n.sendEntries(n.entries)
|
||||||
|
}
|
||||||
|
n.entries = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *discordTypeNotifier) Levels() []log.Level {
|
||||||
|
// TODO: Make this configurable.
|
||||||
|
return []log.Level{
|
||||||
|
log.PanicLevel,
|
||||||
|
log.FatalLevel,
|
||||||
|
log.ErrorLevel,
|
||||||
|
log.WarnLevel,
|
||||||
|
log.InfoLevel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *discordTypeNotifier) Fire(entry *log.Entry) error {
|
||||||
|
if n.entries != nil {
|
||||||
|
n.entries = append(n.entries, entry)
|
||||||
|
} else {
|
||||||
|
// Log output generated outside a cycle is sent immediately.
|
||||||
|
n.sendEntries([]*log.Entry{entry})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type discordWebhookBody struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,8 @@ func NewNotifier(c *cli.Context) *Notifier {
|
||||||
switch t {
|
switch t {
|
||||||
case emailType:
|
case emailType:
|
||||||
tn = newEmailNotifier(c)
|
tn = newEmailNotifier(c)
|
||||||
|
case discordType:
|
||||||
|
tn = newDiscordNotifier(c)
|
||||||
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