feat(notifications): add general notification delay (#1246)

pull/1219/head^2
lazou 3 years ago committed by GitHub
parent f79e4b5435
commit a5c60a9fe6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -26,6 +26,7 @@ comma-separated list of values to the `--notifications` option
- `--notifications-level` (env. `WATCHTOWER_NOTIFICATIONS_LEVEL`): Controls the log level which is used for the notifications. If omitted, the default log level is `info`. Possible values are: `panic`, `fatal`, `error`, `warn`, `info`, `debug` or `trace`. - `--notifications-level` (env. `WATCHTOWER_NOTIFICATIONS_LEVEL`): Controls the log level which is used for the notifications. If omitted, the default log level is `info`. Possible values are: `panic`, `fatal`, `error`, `warn`, `info`, `debug` or `trace`.
- `--notifications-hostname` (env. `WATCHTOWER_NOTIFICATIONS_HOSTNAME`): Custom hostname specified in subject/title. Useful to override the operating system hostname. - `--notifications-hostname` (env. `WATCHTOWER_NOTIFICATIONS_HOSTNAME`): Custom hostname specified in subject/title. Useful to override the operating system hostname.
- `--notifications-delay` (env. `WATCHTOWER_NOTIFICATION_DELAY`): Delay before sending notifications expressed in seconds.
- Watchtower will post a notification every time it is started. This behavior [can be changed](https://containrrr.github.io/watchtower/arguments/#without_sending_a_startup_message) with an argument. - Watchtower will post a notification every time it is started. This behavior [can be changed](https://containrrr.github.io/watchtower/arguments/#without_sending_a_startup_message) with an argument.
## Available services ## Available services

@ -184,6 +184,12 @@ func RegisterNotificationFlags(rootCmd *cobra.Command) {
viper.GetString("WATCHTOWER_NOTIFICATIONS_LEVEL"), viper.GetString("WATCHTOWER_NOTIFICATIONS_LEVEL"),
"The log level used for sending notifications. Possible values: panic, fatal, error, warn, info or debug") "The log level used for sending notifications. Possible values: panic, fatal, error, warn, info or debug")
flags.IntP(
"notifications-delay",
"",
viper.GetInt("WATCHTOWER_NOTIFICATIONS_DELAY"),
"Delay before sending notifications, expressed in seconds")
flags.StringP( flags.StringP(
"notifications-hostname", "notifications-hostname",
"", "",

@ -45,7 +45,7 @@ func AppendLegacyUrls(urls []string, cmd *cobra.Command, title string) ([]string
log.WithError(err).Fatal("could not read notifications argument") log.WithError(err).Fatal("could not read notifications argument")
} }
delay := time.Duration(0) legacyDelay := time.Duration(0)
for _, t := range types { for _, t := range types {
@ -76,14 +76,29 @@ func AppendLegacyUrls(urls []string, cmd *cobra.Command, title string) ([]string
urls = append(urls, shoutrrrURL) urls = append(urls, shoutrrrURL)
if delayNotifier, ok := legacyNotifier.(ty.DelayNotifier); ok { if delayNotifier, ok := legacyNotifier.(ty.DelayNotifier); ok {
delay = delayNotifier.GetDelay() legacyDelay = delayNotifier.GetDelay()
} }
log.WithField("URL", shoutrrrURL).Trace("created Shoutrrr URL from legacy notifier") log.WithField("URL", shoutrrrURL).Trace("created Shoutrrr URL from legacy notifier")
} }
delay := GetDelay(cmd, legacyDelay)
return urls, delay return urls, delay
} }
// GetDelay returns the legacy delay if defined, otherwise the delay as set by args is returned
func GetDelay(c *cobra.Command, legacyDelay time.Duration) time.Duration {
if legacyDelay > 0 {
return legacyDelay
}
delay, _ := c.PersistentFlags().GetInt("notifications-delay")
if delay > 0 {
return time.Duration(delay) * time.Second
}
return time.Duration(0)
}
// GetTitle returns a common notification title with hostname appended // GetTitle returns a common notification title with hostname appended
func GetTitle(hostname string) string { func GetTitle(hostname string) string {
title := "Watchtower updates" title := "Watchtower updates"

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"os" "os"
"time"
"github.com/containrrr/watchtower/cmd" "github.com/containrrr/watchtower/cmd"
"github.com/containrrr/watchtower/internal/flags" "github.com/containrrr/watchtower/internal/flags"
@ -49,6 +50,51 @@ var _ = Describe("notifications", func() {
Expect(title).To(Equal("Watchtower updates")) Expect(title).To(Equal("Watchtower updates"))
}) })
}) })
When("no delay is defined", func() {
It("should use the default delay", func() {
command := cmd.NewRootCommand()
flags.RegisterNotificationFlags(command)
delay := notifications.GetDelay(command, time.Duration(0))
Expect(delay).To(Equal(time.Duration(0)))
})
})
When("delay is defined", func() {
It("should use the specified delay", func() {
command := cmd.NewRootCommand()
flags.RegisterNotificationFlags(command)
err := command.ParseFlags([]string{
"--notifications-delay",
"5",
})
Expect(err).NotTo(HaveOccurred())
delay := notifications.GetDelay(command, time.Duration(0))
Expect(delay).To(Equal(time.Duration(5) * time.Second))
})
})
When("legacy delay is defined", func() {
It("should use the specified legacy delay", func() {
command := cmd.NewRootCommand()
flags.RegisterNotificationFlags(command)
delay := notifications.GetDelay(command, time.Duration(5)*time.Second)
Expect(delay).To(Equal(time.Duration(5) * time.Second))
})
})
When("legacy delay and delay is defined", func() {
It("should use the specified legacy delay and ignore the specified delay", func() {
command := cmd.NewRootCommand()
flags.RegisterNotificationFlags(command)
err := command.ParseFlags([]string{
"--notifications-delay",
"0",
})
Expect(err).NotTo(HaveOccurred())
delay := notifications.GetDelay(command, time.Duration(7)*time.Second)
Expect(delay).To(Equal(time.Duration(7) * time.Second))
})
})
}) })
Describe("the slack notifier", func() { Describe("the slack notifier", func() {
// builderFn := notifications.NewSlackNotifier // builderFn := notifications.NewSlackNotifier
@ -74,11 +120,11 @@ var _ = Describe("notifications", func() {
It("should return a discord url when using a hook url with the domain discord.com", func() { It("should return a discord url when using a hook url with the domain discord.com", func() {
hookURL := fmt.Sprintf("https://%s/api/webhooks/%s/%s/slack", "discord.com", channel, token) hookURL := fmt.Sprintf("https://%s/api/webhooks/%s/%s/slack", "discord.com", channel, token)
testURL(buildArgs(hookURL), expected) testURL(buildArgs(hookURL), expected, time.Duration(0))
}) })
It("should return a discord url when using a hook url with the domain discordapp.com", func() { It("should return a discord url when using a hook url with the domain discordapp.com", func() {
hookURL := fmt.Sprintf("https://%s/api/webhooks/%s/%s/slack", "discordapp.com", channel, token) hookURL := fmt.Sprintf("https://%s/api/webhooks/%s/%s/slack", "discordapp.com", channel, token)
testURL(buildArgs(hookURL), expected) testURL(buildArgs(hookURL), expected, time.Duration(0))
}) })
}) })
When("converting a slack service config into a shoutrrr url", func() { When("converting a slack service config into a shoutrrr url", func() {
@ -99,6 +145,7 @@ var _ = Describe("notifications", func() {
hookURL := fmt.Sprintf("https://hooks.slack.com/services/%s/%s/%s", tokenA, tokenB, tokenC) hookURL := fmt.Sprintf("https://hooks.slack.com/services/%s/%s/%s", tokenA, tokenB, tokenC)
expectedOutput := fmt.Sprintf("slack://hook:%s-%s-%s@webhook?botname=%s&color=%s&icon=%s&title=%s", tokenA, tokenB, tokenC, username, color, url.QueryEscape(iconURL), title) expectedOutput := fmt.Sprintf("slack://hook:%s-%s-%s@webhook?botname=%s&color=%s&icon=%s&title=%s", tokenA, tokenB, tokenC, username, color, url.QueryEscape(iconURL), title)
expectedDelay := time.Duration(7) * time.Second
args := []string{ args := []string{
"--notifications", "--notifications",
@ -109,9 +156,11 @@ var _ = Describe("notifications", func() {
username, username,
"--notification-slack-icon-url", "--notification-slack-icon-url",
iconURL, iconURL,
"--notifications-delay",
fmt.Sprint(expectedDelay.Seconds()),
} }
testURL(args, expectedOutput) testURL(args, expectedOutput, expectedDelay)
}) })
}) })
@ -131,7 +180,7 @@ var _ = Describe("notifications", func() {
iconEmoji, iconEmoji,
} }
testURL(args, expectedOutput) testURL(args, expectedOutput, time.Duration(0))
}) })
}) })
}) })
@ -159,7 +208,7 @@ var _ = Describe("notifications", func() {
token, token,
} }
testURL(args, expectedOutput) testURL(args, expectedOutput, time.Duration(0))
}) })
}) })
}) })
@ -187,7 +236,7 @@ var _ = Describe("notifications", func() {
hookURL, hookURL,
} }
testURL(args, expectedOutput) testURL(args, expectedOutput, time.Duration(0))
}) })
}) })
}) })
@ -197,6 +246,8 @@ var _ = Describe("notifications", func() {
It("should set the from address in the URL", func() { It("should set the from address in the URL", func() {
fromAddress := "lala@example.com" fromAddress := "lala@example.com"
expectedOutput := buildExpectedURL("containrrrbot", "secret-password", "mail.containrrr.dev", 25, fromAddress, "mail@example.com", "Plain") expectedOutput := buildExpectedURL("containrrrbot", "secret-password", "mail.containrrr.dev", 25, fromAddress, "mail@example.com", "Plain")
expectedDelay := time.Duration(7) * time.Second
args := []string{ args := []string{
"--notifications", "--notifications",
"email", "email",
@ -210,8 +261,10 @@ var _ = Describe("notifications", func() {
"secret-password", "secret-password",
"--notification-email-server", "--notification-email-server",
"mail.containrrr.dev", "mail.containrrr.dev",
"--notifications-delay",
fmt.Sprint(expectedDelay.Seconds()),
} }
testURL(args, expectedOutput) testURL(args, expectedOutput, expectedDelay)
}) })
It("should return the expected URL", func() { It("should return the expected URL", func() {
@ -219,6 +272,7 @@ var _ = Describe("notifications", func() {
fromAddress := "sender@example.com" fromAddress := "sender@example.com"
toAddress := "receiver@example.com" toAddress := "receiver@example.com"
expectedOutput := buildExpectedURL("containrrrbot", "secret-password", "mail.containrrr.dev", 25, fromAddress, toAddress, "Plain") expectedOutput := buildExpectedURL("containrrrbot", "secret-password", "mail.containrrr.dev", 25, fromAddress, toAddress, "Plain")
expectedDelay := time.Duration(7) * time.Second
args := []string{ args := []string{
"--notifications", "--notifications",
@ -233,9 +287,11 @@ var _ = Describe("notifications", func() {
"secret-password", "secret-password",
"--notification-email-server", "--notification-email-server",
"mail.containrrr.dev", "mail.containrrr.dev",
"--notification-email-delay",
fmt.Sprint(expectedDelay.Seconds()),
} }
testURL(args, expectedOutput) testURL(args, expectedOutput, expectedDelay)
}) })
}) })
}) })
@ -257,7 +313,7 @@ func buildExpectedURL(username string, password string, host string, port int, f
url.QueryEscape(to)) url.QueryEscape(to))
} }
func testURL(args []string, expectedURL string) { func testURL(args []string, expectedURL string, expectedDelay time.Duration) {
defer GinkgoRecover() defer GinkgoRecover()
command := cmd.NewRootCommand() command := cmd.NewRootCommand()
@ -268,9 +324,10 @@ func testURL(args []string, expectedURL string) {
hostname := notifications.GetHostname(command) hostname := notifications.GetHostname(command)
title := notifications.GetTitle(hostname) title := notifications.GetTitle(hostname)
urls, _ := notifications.AppendLegacyUrls([]string{}, command, title) urls, delay := notifications.AppendLegacyUrls([]string{}, command, title)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(urls).To(ContainElement(expectedURL)) Expect(urls).To(ContainElement(expectedURL))
Expect(delay).To(Equal(expectedDelay))
} }

Loading…
Cancel
Save