diff --git a/docs/notif/telegram.md b/docs/notif/telegram.md index 12d6e7093..42015c412 100644 --- a/docs/notif/telegram.md +++ b/docs/notif/telegram.md @@ -23,6 +23,17 @@ Multiple chat IDs can be provided in order to deliver notifications to multiple Docker tag {{ .Entry.Image }} which you subscribed to through {{ .Entry.Provider }} provider has been released. ``` +!!! example "File with templateFile" + ```yaml + notif: + telegram: + token: aabbccdd:11223344 + chatIDs: + - "123456789" + - "987654321" + templateFile: /path/to/telegram-template.txt + ``` + | Name | Default | Description | |-----------------------|------------------------------------|---------------------------------------------------------------------------| | `token` | | Telegram bot token | @@ -30,6 +41,7 @@ Multiple chat IDs can be provided in order to deliver notifications to multiple | `chatIDs` | | List of [chat IDs](#chatids-format) to send notifications to | | `chatIDsFile` | | Use content of secret file as chat IDs if `chatIDs` not defined | | `templateBody`[^1] | See [below](#default-templatebody) | [Notification template](../faq.md#notification-template) for message body | +| `templateFile` | | Use content of file as template body if `templateBody` not defined | | `disableNotification` | `false` | Send silent message with no sound | !!! abstract "Environment variables" @@ -38,6 +50,7 @@ Multiple chat IDs can be provided in order to deliver notifications to multiple * `DIUN_NOTIF_TELEGRAM_CHATIDS` (comma separated) * `DIUN_NOTIF_TELEGRAM_CHATIDSFILE` * `DIUN_NOTIF_TELEGRAM_TEMPLATEBODY` + * `DIUN_NOTIF_TELEGRAM_TEMPLATEFILE` * `DIUN_NOTIF_TELEGRAM_DISABLENOTIFICATION` !!! example "chat IDs secret file" diff --git a/internal/app/job.go b/internal/app/job.go index 5271d8210..079637e5d 100644 --- a/internal/app/job.go +++ b/internal/app/job.go @@ -51,11 +51,11 @@ func (di *Diun) createJob(job model.Job) { reg = (&model.RegOpt{}).GetDefaults() } - regUser, err := utl.GetSecret(reg.Username, reg.UsernameFile) + regUser, err := utl.GetValueOrFileContents(reg.Username, reg.UsernameFile) if err != nil { log.Warn().Err(err).Msgf("Cannot retrieve username secret for regopts %s", reg.Name) } - regPassword, err := utl.GetSecret(reg.Password, reg.PasswordFile) + regPassword, err := utl.GetValueOrFileContents(reg.Password, reg.PasswordFile) if err != nil { log.Warn().Err(err).Msgf("Cannot retrieve password secret for regopts %s", reg.Name) } diff --git a/internal/model/notif_telegram.go b/internal/model/notif_telegram.go index d4d13e32e..8f01e1bfd 100644 --- a/internal/model/notif_telegram.go +++ b/internal/model/notif_telegram.go @@ -12,6 +12,7 @@ type NotifTelegram struct { ChatIDs []string `yaml:"chatIDs,omitempty" json:"chatIDs,omitempty" validate:"omitempty"` ChatIDsFile string `yaml:"chatIDsFile,omitempty" json:"chatIDsFile,omitempty" validate:"omitempty,file"` TemplateBody string `yaml:"templateBody,omitempty" json:"templateBody,omitempty" validate:"required"` + TemplateFile string `yaml:"templateFile,omitempty" json:"templateFile,omitempty" validate:"omitempty,file"` DisableNotification *bool `yaml:"disableNotification,omitempty" json:"disableNotification,omitempty" validate:"omitempty"` } diff --git a/internal/notif/amqp/client.go b/internal/notif/amqp/client.go index afe5991bd..c3891f1d3 100644 --- a/internal/notif/amqp/client.go +++ b/internal/notif/amqp/client.go @@ -34,12 +34,12 @@ func (c *Client) Name() string { // Send creates and sends a amqp notification with an entry func (c *Client) Send(entry model.NotifEntry) error { - username, err := utl.GetSecret(c.cfg.Username, c.cfg.UsernameFile) + username, err := utl.GetValueOrFileContents(c.cfg.Username, c.cfg.UsernameFile) if err != nil { return err } - password, err := utl.GetSecret(c.cfg.Password, c.cfg.PasswordFile) + password, err := utl.GetValueOrFileContents(c.cfg.Password, c.cfg.PasswordFile) if err != nil { return err } diff --git a/internal/notif/apprise/client.go b/internal/notif/apprise/client.go index a6d9bd66c..3b341b7cc 100644 --- a/internal/notif/apprise/client.go +++ b/internal/notif/apprise/client.go @@ -77,7 +77,7 @@ func (c *Client) Send(entry model.NotifEntry) error { u.Path = path.Join(u.Path, "notify") if c.cfg.Token != "" || c.cfg.TokenFile != "" { - token, err := utl.GetSecret(c.cfg.Token, c.cfg.TokenFile) + token, err := utl.GetValueOrFileContents(c.cfg.Token, c.cfg.TokenFile) if err != nil { return errors.Wrap(err, "cannot retrieve token secret for Apprise notifier") } diff --git a/internal/notif/discord/client.go b/internal/notif/discord/client.go index cad9ba9c6..6e3098e10 100644 --- a/internal/notif/discord/client.go +++ b/internal/notif/discord/client.go @@ -43,7 +43,7 @@ func (c *Client) Name() string { func (c *Client) Send(entry model.NotifEntry) error { var content bytes.Buffer - webhookURL, err := utl.GetSecret(c.cfg.WebhookURL, c.cfg.WebhookURLFile) + webhookURL, err := utl.GetValueOrFileContents(c.cfg.WebhookURL, c.cfg.WebhookURLFile) if err != nil { return errors.Wrap(err, "cannot retrieve webhook URL for Discord notifier") } diff --git a/internal/notif/elasticsearch/client.go b/internal/notif/elasticsearch/client.go index f2d4b4a3e..1f1a8b668 100644 --- a/internal/notif/elasticsearch/client.go +++ b/internal/notif/elasticsearch/client.go @@ -40,12 +40,12 @@ func (c *Client) Name() string { // Send creates and sends an elasticsearch notification with an entry func (c *Client) Send(entry model.NotifEntry) error { - username, err := utl.GetSecret(c.cfg.Username, c.cfg.UsernameFile) + username, err := utl.GetValueOrFileContents(c.cfg.Username, c.cfg.UsernameFile) if err != nil { return err } - password, err := utl.GetSecret(c.cfg.Password, c.cfg.PasswordFile) + password, err := utl.GetValueOrFileContents(c.cfg.Password, c.cfg.PasswordFile) if err != nil { return err } diff --git a/internal/notif/gotify/client.go b/internal/notif/gotify/client.go index 6c27d6743..f9c0fc460 100644 --- a/internal/notif/gotify/client.go +++ b/internal/notif/gotify/client.go @@ -40,7 +40,7 @@ func (c *Client) Name() string { // Send creates and sends a gotify notification with an entry func (c *Client) Send(entry model.NotifEntry) error { - token, err := utl.GetSecret(c.cfg.Token, c.cfg.TokenFile) + token, err := utl.GetValueOrFileContents(c.cfg.Token, c.cfg.TokenFile) if err != nil { return errors.Wrap(err, "cannot retrieve token secret for Gotify notifier") } diff --git a/internal/notif/mail/client.go b/internal/notif/mail/client.go index cf66e07e3..0cf98a883 100644 --- a/internal/notif/mail/client.go +++ b/internal/notif/mail/client.go @@ -113,11 +113,11 @@ func (c *Client) Send(entry model.NotifEntry) error { } } - username, err := utl.GetSecret(c.cfg.Username, c.cfg.UsernameFile) + username, err := utl.GetValueOrFileContents(c.cfg.Username, c.cfg.UsernameFile) if err != nil { log.Warn().Err(err).Msg("Cannot retrieve username secret for mail notifier") } - password, err := utl.GetSecret(c.cfg.Password, c.cfg.PasswordFile) + password, err := utl.GetValueOrFileContents(c.cfg.Password, c.cfg.PasswordFile) if err != nil { log.Warn().Err(err).Msg("Cannot retrieve password secret for mail notifier") } diff --git a/internal/notif/matrix/client.go b/internal/notif/matrix/client.go index 37be85a5b..65034a277 100644 --- a/internal/notif/matrix/client.go +++ b/internal/notif/matrix/client.go @@ -46,11 +46,11 @@ func (c *Client) Send(entry model.NotifEntry) error { } }() - user, err := utl.GetSecret(c.cfg.User, c.cfg.UserFile) + user, err := utl.GetValueOrFileContents(c.cfg.User, c.cfg.UserFile) if err != nil { return errors.Wrap(err, "cannot retrieve username secret for Matrix notifier") } - password, err := utl.GetSecret(c.cfg.Password, c.cfg.PasswordFile) + password, err := utl.GetValueOrFileContents(c.cfg.Password, c.cfg.PasswordFile) if err != nil { return errors.Wrap(err, "cannot retrieve password secret for Matrix notifier") } diff --git a/internal/notif/mqtt/client.go b/internal/notif/mqtt/client.go index d3b55a760..518dee9df 100644 --- a/internal/notif/mqtt/client.go +++ b/internal/notif/mqtt/client.go @@ -35,12 +35,12 @@ func (c *Client) Name() string { // Send creates and sends a mqtt notification with an entry func (c *Client) Send(entry model.NotifEntry) error { - username, err := utl.GetSecret(c.cfg.Username, c.cfg.UsernameFile) + username, err := utl.GetValueOrFileContents(c.cfg.Username, c.cfg.UsernameFile) if err != nil { return err } - password, err := utl.GetSecret(c.cfg.Password, c.cfg.PasswordFile) + password, err := utl.GetValueOrFileContents(c.cfg.Password, c.cfg.PasswordFile) if err != nil { return err } diff --git a/internal/notif/ntfy/client.go b/internal/notif/ntfy/client.go index 71878510e..0760752eb 100644 --- a/internal/notif/ntfy/client.go +++ b/internal/notif/ntfy/client.go @@ -100,7 +100,7 @@ func (c *Client) Send(entry model.NotifEntry) error { return err } - if token, err := utl.GetSecret(c.cfg.Token, c.cfg.TokenFile); err == nil && token != "" { + if token, err := utl.GetValueOrFileContents(c.cfg.Token, c.cfg.TokenFile); err == nil && token != "" { req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) } req.Header.Set("Content-Type", "application/json") diff --git a/internal/notif/pushover/client.go b/internal/notif/pushover/client.go index f942b1603..ea79d7bbe 100644 --- a/internal/notif/pushover/client.go +++ b/internal/notif/pushover/client.go @@ -43,14 +43,14 @@ func (c *Client) Name() string { // Send creates and sends a Pushover notification with an entry func (c *Client) Send(entry model.NotifEntry) error { - token, err := utl.GetSecret(c.cfg.Token, c.cfg.TokenFile) + token, err := utl.GetValueOrFileContents(c.cfg.Token, c.cfg.TokenFile) if err != nil { return errors.Wrap(err, "cannot retrieve token secret for Pushover notifier") } else if token == "" { return errors.New("Pushover API token cannot be empty") } - recipient, err := utl.GetSecret(c.cfg.Recipient, c.cfg.RecipientFile) + recipient, err := utl.GetValueOrFileContents(c.cfg.Recipient, c.cfg.RecipientFile) if err != nil { return errors.Wrap(err, "cannot retrieve recipient secret for Pushover notifier") } else if recipient == "" { diff --git a/internal/notif/rocketchat/client.go b/internal/notif/rocketchat/client.go index 7577bfe4d..e389786e1 100644 --- a/internal/notif/rocketchat/client.go +++ b/internal/notif/rocketchat/client.go @@ -42,7 +42,7 @@ func (c *Client) Name() string { // Send creates and sends a rocketchat notification with an entry // https://rocket.chat/docs/developer-guides/rest-api/chat/postmessage/ func (c *Client) Send(entry model.NotifEntry) error { - token, err := utl.GetSecret(c.cfg.Token, c.cfg.TokenFile) + token, err := utl.GetValueOrFileContents(c.cfg.Token, c.cfg.TokenFile) if err != nil { return errors.Wrap(err, "cannot retrieve token secret for RocketChat notifier") } diff --git a/internal/notif/slack/client.go b/internal/notif/slack/client.go index 13005d957..67526f4c5 100644 --- a/internal/notif/slack/client.go +++ b/internal/notif/slack/client.go @@ -38,7 +38,7 @@ func (c *Client) Name() string { // Send creates and sends a slack notification with an entry func (c *Client) Send(entry model.NotifEntry) error { - webhookURL, err := utl.GetSecret(c.cfg.WebhookURL, c.cfg.WebhookURLFile) + webhookURL, err := utl.GetValueOrFileContents(c.cfg.WebhookURL, c.cfg.WebhookURLFile) if err != nil { return errors.Wrap(err, "cannot retrieve webhook URL for Slack notifier") } diff --git a/internal/notif/teams/client.go b/internal/notif/teams/client.go index 1bd565ea2..5cb7066bd 100644 --- a/internal/notif/teams/client.go +++ b/internal/notif/teams/client.go @@ -52,7 +52,7 @@ type Fact struct { // Send creates and sends a webhook notification with an entry func (c *Client) Send(entry model.NotifEntry) error { - webhookURL, err := utl.GetSecret(c.cfg.WebhookURL, c.cfg.WebhookURLFile) + webhookURL, err := utl.GetValueOrFileContents(c.cfg.WebhookURL, c.cfg.WebhookURLFile) if err != nil { return errors.Wrap(err, "cannot retrieve webhook URL for Teams notifier") } diff --git a/internal/notif/telegram/client.go b/internal/notif/telegram/client.go index 6bbadec59..b7f0d09e8 100644 --- a/internal/notif/telegram/client.go +++ b/internal/notif/telegram/client.go @@ -44,13 +44,13 @@ func (c *Client) Name() string { // Send creates and sends a Telegram notification with an entry func (c *Client) Send(entry model.NotifEntry) error { - token, err := utl.GetSecret(c.cfg.Token, c.cfg.TokenFile) + token, err := utl.GetValueOrFileContents(c.cfg.Token, c.cfg.TokenFile) if err != nil { return errors.Wrap(err, "cannot retrieve token secret for Telegram notifier") } cids := c.cfg.ChatIDs - cidsRaw, err := utl.GetSecret("", c.cfg.ChatIDsFile) + cidsRaw, err := utl.GetValueOrFileContents("", c.cfg.ChatIDsFile) if err != nil { return errors.Wrap(err, "cannot retrieve chat IDs secret for Telegram notifier") } @@ -81,10 +81,15 @@ func (c *Client) Send(entry model.NotifEntry) error { return errors.Wrap(err, "failed to create telegram bot client") } + templateBody, err := utl.GetValueOrFileContents(c.cfg.TemplateBody, c.cfg.TemplateFile) + if err != nil { + return errors.Wrap(err, "cannot get template for Telegram notifier") + } + message, err := msg.New(msg.Options{ Meta: c.meta, Entry: entry, - TemplateBody: c.cfg.TemplateBody, + TemplateBody: templateBody, TemplateFuncs: template.FuncMap{ "escapeMarkdown": func(text string) string { text = strings.ReplaceAll(text, "_", "\\_") diff --git a/pkg/k8s/client.go b/pkg/k8s/client.go index dbd2ef51a..086e0d869 100644 --- a/pkg/k8s/client.go +++ b/pkg/k8s/client.go @@ -93,7 +93,7 @@ func newExternalClusterClient(opts Options) (*kubernetes.Clientset, error) { return nil, errors.New("endpoint missing for external cluster client") } - opts.Token, err = utl.GetSecret(opts.Token, opts.TokenFile) + opts.Token, err = utl.GetValueOrFileContents(opts.Token, opts.TokenFile) if err != nil { return nil, errors.Wrap(err, "cannot retrieve bearer token") } diff --git a/pkg/utl/utl.go b/pkg/utl/utl.go index f6973dca0..cb1069c52 100644 --- a/pkg/utl/utl.go +++ b/pkg/utl/utl.go @@ -53,8 +53,10 @@ func GetEnv(key, fallback string) string { return fallback } -// GetSecret retrieves secret's value from plaintext or filename if defined -func GetSecret(plaintext, filename string) (string, error) { +// GetValueOrFileContents retrieves a value from plaintext or filename if defined. +// This function can be used for secrets, templates, or any content that needs +// to be loaded either from a direct value or from a file. +func GetValueOrFileContents(plaintext, filename string) (string, error) { if plaintext != "" { return plaintext, nil } else if filename != "" {