mirror of
https://github.com/containrrr/watchtower.git
synced 2025-09-21 21:30:48 +02:00
Add support for Gotify notifications (#346)
This adds support for Gotify (https://gotify.net) notifications. Work items: * Two flags have been added to internal/flags/flags.go: "notification-gotify-url" and "notification-gotify-token". * A Gotify notification driver has been added in notifications/gotify.go. * "gotify" has been added to notification driver choices in notifications/notifier.go. * Docs have been updated
This commit is contained in:
parent
d744b5ddf7
commit
dff16dc639
4 changed files with 131 additions and 2 deletions
|
@ -1,4 +1,4 @@
|
||||||
|
|
||||||
# Notifications
|
# Notifications
|
||||||
|
|
||||||
Watchtower can send notifications when containers are updated. Notifications are sent via hooks in the logging system, [logrus](http://github.com/sirupsen/logrus).
|
Watchtower can send notifications when containers are updated. Notifications are sent via hooks in the logging system, [logrus](http://github.com/sirupsen/logrus).
|
||||||
|
@ -7,6 +7,7 @@ The types of notifications to send are passed via the comma-separated option `--
|
||||||
- `email` to send notifications via e-mail
|
- `email` to send notifications via e-mail
|
||||||
- `slack` to send notifications through a Slack webhook
|
- `slack` to send notifications through a Slack webhook
|
||||||
- `msteams` to send notifications via MSTeams webhook
|
- `msteams` to send notifications via MSTeams webhook
|
||||||
|
- `gotify` to send notifications via Gotify
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
|
|
||||||
|
@ -90,3 +91,18 @@ docker run -d \
|
||||||
-e WATCHTOWER_NOTIFICATION_MSTEAMS_USE_LOG_DATA=true \
|
-e WATCHTOWER_NOTIFICATION_MSTEAMS_USE_LOG_DATA=true \
|
||||||
containrrr/watchtower
|
containrrr/watchtower
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Gotify
|
||||||
|
|
||||||
|
To push a notification to your Gotify instance, register a Gotify app and specify the Gotify URL and app token:
|
||||||
|
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
--name watchtower \
|
||||||
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
-e WATCHTOWER_NOTIFICATIONS=gotify \
|
||||||
|
-e WATCHTOWER_NOTIFICATION_GOTIFY_URL="https://my.gotify.tld/" \
|
||||||
|
-e WATCHTOWER_NOTIFICATION_GOTIFY_TOKEN="SuperSecretToken" \
|
||||||
|
containrrr/watchtower
|
||||||
|
```
|
||||||
|
|
|
@ -98,7 +98,7 @@ func RegisterNotificationFlags(rootCmd *cobra.Command) {
|
||||||
"notifications",
|
"notifications",
|
||||||
"n",
|
"n",
|
||||||
viper.GetStringSlice("WATCHTOWER_NOTIFICATIONS"),
|
viper.GetStringSlice("WATCHTOWER_NOTIFICATIONS"),
|
||||||
" notification types to send (valid: email, slack, msteams")
|
" notification types to send (valid: email, slack, msteams, gotify)")
|
||||||
|
|
||||||
flags.StringP(
|
flags.StringP(
|
||||||
"notifications-level",
|
"notifications-level",
|
||||||
|
@ -192,6 +192,17 @@ Should only be used for testing.
|
||||||
"",
|
"",
|
||||||
viper.GetBool("WATCHTOWER_NOTIFICATION_MSTEAMS_USE_LOG_DATA"),
|
viper.GetBool("WATCHTOWER_NOTIFICATION_MSTEAMS_USE_LOG_DATA"),
|
||||||
"The MSTeams notifier will try to extract log entry fields as MSTeams message facts")
|
"The MSTeams notifier will try to extract log entry fields as MSTeams message facts")
|
||||||
|
|
||||||
|
flags.StringP(
|
||||||
|
"notification-gotify-url",
|
||||||
|
"",
|
||||||
|
viper.GetString("WATCHTOWER_NOTIFICATION_GOTIFY_URL"),
|
||||||
|
"The Gotify URL to send notifications to")
|
||||||
|
flags.StringP(
|
||||||
|
"notification-gotify-token",
|
||||||
|
"",
|
||||||
|
viper.GetString("WATCHTOWER_NOTIFICATION_GOTIFY_TOKEN"),
|
||||||
|
"The Gotify Application required to query the Gotify API")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDefaults provides default values for environment variables
|
// SetDefaults provides default values for environment variables
|
||||||
|
|
100
notifications/gotify.go
Normal file
100
notifications/gotify.go
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
package notifications
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
gotifyType = "gotify"
|
||||||
|
)
|
||||||
|
|
||||||
|
type gotifyTypeNotifier struct {
|
||||||
|
gotifyURL string
|
||||||
|
gotifyAppToken string
|
||||||
|
logLevels []log.Level
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGotifyNotifier(c *cobra.Command, acceptedLogLevels []log.Level) typeNotifier {
|
||||||
|
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 fpr Gotify is insecure")
|
||||||
|
}
|
||||||
|
|
||||||
|
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.")
|
||||||
|
}
|
||||||
|
|
||||||
|
n := &gotifyTypeNotifier{
|
||||||
|
gotifyURL: gotifyURL,
|
||||||
|
gotifyAppToken: gotifyToken,
|
||||||
|
logLevels: acceptedLogLevels,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.AddHook(n)
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *gotifyTypeNotifier) StartNotification() {}
|
||||||
|
|
||||||
|
func (n *gotifyTypeNotifier) SendNotification() {}
|
||||||
|
|
||||||
|
func (n *gotifyTypeNotifier) Levels() []log.Level {
|
||||||
|
return n.logLevels
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *gotifyTypeNotifier) getURL() string {
|
||||||
|
url := n.gotifyURL
|
||||||
|
if !strings.HasSuffix(url, "/") {
|
||||||
|
url += "/"
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonBodyBuffer := bytes.NewBuffer([]byte(jsonBody))
|
||||||
|
resp, err := http.Post(n.getURL(), "application/json", jsonBodyBuffer)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to send Gotify notification: ", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
fmt.Printf("Gotify notification returned %d HTTP status code", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
}()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type gotifyMessage struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Priority int `json:"priority"`
|
||||||
|
}
|
|
@ -38,6 +38,8 @@ func NewNotifier(c *cobra.Command) *Notifier {
|
||||||
tn = newSlackNotifier(c, acceptedLogLevels)
|
tn = newSlackNotifier(c, acceptedLogLevels)
|
||||||
case msTeamsType:
|
case msTeamsType:
|
||||||
tn = newMsTeamsNotifier(c, acceptedLogLevels)
|
tn = newMsTeamsNotifier(c, acceptedLogLevels)
|
||||||
|
case gotifyType:
|
||||||
|
tn = newGotifyNotifier(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