diff --git a/go.mod b/go.mod
index 0c138c0433e..4b8a65616a9 100644
--- a/go.mod
+++ b/go.mod
@@ -54,7 +54,6 @@ require (
require (
cloud.google.com/go/storage v1.40.0
- github.com/Masterminds/sprig/v3 v3.2.1
github.com/alecthomas/chroma/v2 v2.12.0
github.com/alecthomas/kingpin/v2 v2.4.0
github.com/aws/aws-sdk-go v1.53.16
@@ -64,7 +63,7 @@ require (
github.com/google/go-github/v57 v57.0.0
github.com/google/uuid v1.6.0
github.com/grafana-tools/sdk v0.0.0-20220919052116-6562121319fc
- github.com/grafana/alerting v0.0.0-20240607182251-835aff588914
+ github.com/grafana/alerting v0.0.0-20240618145205-cdfc0e849e0b
github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/hashicorp/vault/api v1.10.0
@@ -87,7 +86,6 @@ require (
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f
google.golang.org/api v0.183.0
google.golang.org/protobuf v1.34.1
- gopkg.in/mail.v2 v2.3.1
sigs.k8s.io/kustomize/kyaml v0.16.0
)
@@ -100,6 +98,7 @@ require (
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
+ github.com/Masterminds/sprig/v3 v3.2.1 // indirect
github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 // indirect
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
@@ -130,6 +129,7 @@ require (
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
+ gopkg.in/mail.v2 v2.3.1 // indirect
gopkg.in/telebot.v3 v3.2.1 // indirect
k8s.io/apimachinery v0.29.3 // indirect
k8s.io/client-go v0.29.3 // indirect
diff --git a/go.sum b/go.sum
index 03b4c42d396..7e91ad1c2fe 100644
--- a/go.sum
+++ b/go.sum
@@ -513,8 +513,8 @@ github.com/gosimple/slug v1.1.1 h1:fRu/digW+NMwBIP+RmviTK97Ho/bEj/C9swrCspN3D4=
github.com/gosimple/slug v1.1.1/go.mod h1:ER78kgg1Mv0NQGlXiDe57DpCyfbNywXXZ9mIorhxAf0=
github.com/grafana-tools/sdk v0.0.0-20220919052116-6562121319fc h1:PXZQA2WCxe85Tnn+WEvr8fDpfwibmEPgfgFEaC87G24=
github.com/grafana-tools/sdk v0.0.0-20220919052116-6562121319fc/go.mod h1:AHHlOEv1+GGQ3ktHMlhuTUwo3zljV3QJbC0+8o2kn+4=
-github.com/grafana/alerting v0.0.0-20240607182251-835aff588914 h1:WXLbSnnomltxdNcE20CI8RD8quZ/L0YpXP0WK+0S1BU=
-github.com/grafana/alerting v0.0.0-20240607182251-835aff588914/go.mod h1:U7Ta3K4T7jVgqGSYuPsfuPKHFiL2GbCZSHa3nHjmCos=
+github.com/grafana/alerting v0.0.0-20240618145205-cdfc0e849e0b h1:M86NakDlsYjYqEp/1kR54mhTjxYXTa59vl2pWhgi3f4=
+github.com/grafana/alerting v0.0.0-20240618145205-cdfc0e849e0b/go.mod h1:my6It91EE/AanRkHj3hVjglp3mhuFNxSptm1etLSKHg=
github.com/grafana/dskit v0.0.0-20240611171734-87c7e9e7a4fe h1:PpBnljz9oYSp05pCcQl27n69cL9fNeFH+wkG/ga6oGs=
github.com/grafana/dskit v0.0.0-20240611171734-87c7e9e7a4fe/go.mod h1:HvSf3uf8Ps2vPpzHeAFyZTdUcbVr+Rxpq1xcx7J/muc=
github.com/grafana/e2e v0.1.2-0.20240118170847-db90b84177fc h1:BW+LjKJDz0So5LI8UZfW5neWeKpSkWqhmGjQFzcFfLM=
diff --git a/pkg/alertmanager/alertmanager.go b/pkg/alertmanager/alertmanager.go
index 39822e0dcbe..6f59d15ba36 100644
--- a/pkg/alertmanager/alertmanager.go
+++ b/pkg/alertmanager/alertmanager.go
@@ -6,13 +6,11 @@
package alertmanager
import (
- "bytes"
"context"
"crypto/md5"
"encoding/binary"
"encoding/json"
"fmt"
- htmlTemplate "html/template"
"net/http"
"net/url"
"path"
@@ -21,7 +19,6 @@ import (
"sync"
"time"
- "github.com/Masterminds/sprig/v3"
"github.com/go-kit/log"
"github.com/go-kit/log/level"
"github.com/grafana/alerting/definition"
@@ -29,6 +26,7 @@ import (
alertingNotify "github.com/grafana/alerting/notify"
"github.com/grafana/alerting/notify/nfstatus"
alertingReceivers "github.com/grafana/alerting/receivers"
+ alertingTemplates "github.com/grafana/alerting/templates"
"github.com/grafana/dskit/flagext"
"github.com/pkg/errors"
"github.com/prometheus/alertmanager/api"
@@ -317,19 +315,6 @@ func New(cfg *Config, reg *prometheus.Registry) (*Alertmanager, error) {
am.dispatcherMetrics = dispatch.NewDispatcherMetrics(true, am.registry)
- mailTemplates = htmlTemplate.New("name")
- mailTemplates.Funcs(htmlTemplate.FuncMap{
- "Subject": subjectTemplateFunc,
- "HiddenSubject": hiddenSubjectTemplateFunc,
- "__dangerouslyInjectHTML": __dangerouslyInjectHTML,
- })
- mailTemplates.Funcs(sprig.FuncMap())
- if _, err := mailTemplates.ParseFiles("./templates/ng_alert_notification.html"); err != nil {
- return nil, err
- }
-
- fmt.Println("Parsed:", mailTemplates.Templates())
-
//TODO: From this point onward, the alertmanager _might_ receive requests - we need to make sure we've settled and are ready.
return am, nil
}
@@ -389,6 +374,10 @@ func (am *Alertmanager) ApplyConfig(userID string, conf *definition.PostableApiA
}
tmpl.ExternalURL = am.cfg.ExternalURL
+ if err := tmpl.Parse(strings.NewReader(alertingTemplates.DefaultTemplateString)); err != nil {
+ return err
+ }
+
cfg := definition.GrafanaToUpstreamConfig(conf)
am.api.Update(&cfg, func(_ model.LabelSet) {})
@@ -547,27 +536,22 @@ func buildIntegrationsMap(gCfg *config.GlobalConfig, externalURL string, nc []*d
func buildGrafanaReceiverIntegrations(gCfg *config.GlobalConfig, externalURL string, rcv *definition.PostableApiReceiver, tmpl *template.Template, logger log.Logger) ([]*nfstatus.Integration, error) {
loggerFactory := newLoggerFactory(logger)
- smtpCfg := SmtpConfig{
- AuthPassword: string(gCfg.SMTPAuthPassword),
- AuthUser: gCfg.SMTPAuthUsername,
- CertFile: gCfg.HTTPConfig.TLSConfig.CertFile,
- ContentTypes: []string{}, // (?)
- EhloIdentity: gCfg.SMTPHello,
- ExternalURL: externalURL,
- FromAddress: gCfg.SMTPFrom,
- FromName: "Grafana",
- Host: gCfg.SMTPSmarthost.String(),
- KeyFile: gCfg.HTTPConfig.TLSConfig.KeyFile,
- SkipVerify: !gCfg.SMTPRequireTLS,
- StartTLSPolicy: "", // (?)
- StaticHeaders: map[string]string{}, // (?)
+ emailCfg := alertingReceivers.EmailSenderConfig{
+ AuthPassword: string(gCfg.SMTPAuthPassword),
+ AuthUser: gCfg.SMTPAuthUsername,
+ CertFile: gCfg.HTTPConfig.TLSConfig.CertFile,
+ EhloIdentity: gCfg.SMTPHello,
+ ExternalURL: externalURL,
+ FromAddress: gCfg.SMTPFrom,
+ FromName: "Grafana",
+ Host: gCfg.SMTPSmarthost.String(),
+ KeyFile: gCfg.HTTPConfig.TLSConfig.KeyFile,
+ SkipVerify: !gCfg.SMTPRequireTLS,
+ StaticHeaders: map[string]string{}, // (?)
}
whFn := func(n alertingReceivers.Metadata) (alertingReceivers.WebhookSender, error) {
- return NewSender(logger, smtpCfg), nil
- }
- emailFn := func(n alertingReceivers.Metadata) (alertingReceivers.EmailSender, error) {
- return NewSender(logger, smtpCfg), nil
+ return NewSender(logger), nil
}
// The decrypt functions and the context are used to decrypt the configuration.
@@ -583,7 +567,7 @@ func buildGrafanaReceiverIntegrations(gCfg *config.GlobalConfig, externalURL str
&images.UnavailableProvider{}, // TODO: include images in notifications
loggerFactory,
whFn,
- emailFn,
+ alertingReceivers.NewEmailSenderFactory(emailCfg),
1, // orgID is always 1.
version.Version,
)
@@ -860,43 +844,3 @@ func alertSize(alert model.Alert) int {
size += len(alert.GeneratorURL)
return size
}
-
-// hiddenSubjectTemplateFunc sets the subject template (value) on the map represented by `.Subject.` (obj) so that it can be compiled and executed later.
-// It returns a blank string, so there will be no resulting value left in place of the template.
-func hiddenSubjectTemplateFunc(obj map[string]any, value string) string {
- obj["value"] = value
- return ""
-}
-
-// subjectTemplateFunc does the same thing has hiddenSubjectTemplateFunc, but in addition it executes and returns the subject template using the data represented in `.TemplateData` (data)
-// This results in the template being replaced by the subject string.
-func subjectTemplateFunc(obj map[string]any, data map[string]any, value string) string {
- obj["value"] = value
-
- titleTmpl, err := htmlTemplate.New("title").Parse(value)
- if err != nil {
- return ""
- }
-
- var buf bytes.Buffer
- err = titleTmpl.ExecuteTemplate(&buf, "title", data)
- if err != nil {
- return ""
- }
-
- subj := buf.String()
- // Since we have already executed the template, save it to subject data so we don't have to do it again later on
- obj["executed_template"] = subj
- return subj
-}
-
-// __dangerouslyInjectHTML allows marking areas of am email template as HTML safe, this will _not_ sanitize the string and will allow HTML snippets to be rendered verbatim.
-// Use with absolute care as this _could_ allow for XSS attacks when used in an insecure context.
-//
-// It's safe to ignore gosec warning G203 when calling this function in an HTML template because we assume anyone who has write access
-// to the email templates folder is an administrator.
-//
-// nolint:gosec
-func __dangerouslyInjectHTML(s string) htmlTemplate.HTML {
- return htmlTemplate.HTML(s)
-}
diff --git a/pkg/alertmanager/sender.go b/pkg/alertmanager/sender.go
index 1e95096bc14..e81a1331096 100644
--- a/pkg/alertmanager/sender.go
+++ b/pkg/alertmanager/sender.go
@@ -51,7 +51,7 @@ type Sender struct {
smtp SmtpConfig
}
-func NewSender(log log.Logger, cfg SmtpConfig) *Sender {
+func NewSender(log log.Logger) *Sender {
netTransport := &http.Transport{
TLSClientConfig: &tls.Config{
Renegotiation: tls.RenegotiateFreelyAsClient,
@@ -67,9 +67,8 @@ func NewSender(log log.Logger, cfg SmtpConfig) *Sender {
Transport: netTransport,
}
return &Sender{
- c: c,
- log: log,
- smtp: cfg,
+ c: c,
+ log: log,
}
}
diff --git a/pkg/alertmanager/sender_test.go b/pkg/alertmanager/sender_test.go
index db4c7bfe9d4..7bdf720f6a5 100644
--- a/pkg/alertmanager/sender_test.go
+++ b/pkg/alertmanager/sender_test.go
@@ -26,7 +26,7 @@ func TestSendWebhook(t *testing.T) {
got = r
w.WriteHeader(http.StatusOK)
}))
- s := NewSender(alertingLogging.FakeLogger{}, SmtpConfig{})
+ s := NewSender(alertingLogging.FakeLogger{})
// The method should be either POST or PUT.
cmd := alertingReceivers.SendWebhookSettings{
diff --git a/pkg/alertmanager/sender_email.go b/vendor/github.com/grafana/alerting/receivers/email_sender.go
similarity index 57%
rename from pkg/alertmanager/sender_email.go
rename to vendor/github.com/grafana/alerting/receivers/email_sender.go
index 0beaba5d64c..bb33da95b54 100644
--- a/pkg/alertmanager/sender_email.go
+++ b/vendor/github.com/grafana/alerting/receivers/email_sender.go
@@ -1,9 +1,10 @@
-package alertmanager
+package receivers
import (
"bytes"
"context"
"crypto/tls"
+ _ "embed"
"fmt"
"html/template"
"io"
@@ -12,12 +13,56 @@ import (
"strconv"
"strings"
- alertingReceivers "github.com/grafana/alerting/receivers"
- "github.com/grafana/mimir/pkg/util/version"
+ "github.com/Masterminds/sprig/v3"
+ "github.com/grafana/alerting/templates"
gomail "gopkg.in/mail.v2"
)
-var mailTemplates *template.Template
+type defaultEmailSender struct {
+ cfg EmailSenderConfig
+ tmpl *template.Template
+}
+
+type EmailSenderConfig struct {
+ AuthPassword string
+ AuthUser string
+ CertFile string
+ EhloIdentity string
+ ExternalURL string
+ FromName string
+ FromAddress string
+ Host string
+ KeyFile string
+ SkipVerify bool
+ StaticHeaders map[string]string
+ Version string
+}
+
+//go:embed templates/ng_alert_notification.html
+var defaultEmailTemplate string
+
+// NewEmailSenderFactory takes a configuration and returns a new EmailSender factory function.
+func NewEmailSenderFactory(cfg EmailSenderConfig) func(n Metadata) (EmailSender, error) {
+ return func(n Metadata) (EmailSender, error) {
+ tmpl, err := template.New("ng_alert_notification").
+ Funcs(template.FuncMap{
+ "Subject": subjectTemplateFunc,
+ "HiddenSubject": hiddenSubjectTemplateFunc,
+ "__dangerouslyInjectHTML": __dangerouslyInjectHTML,
+ }).
+ Funcs(template.FuncMap(templates.DefaultFuncs)).
+ Funcs(sprig.FuncMap()).
+ Parse(defaultEmailTemplate)
+ if err != nil {
+ return nil, err
+ }
+
+ return &defaultEmailSender{
+ cfg: cfg,
+ tmpl: tmpl,
+ }, nil
+ }
+}
// AttachedFile is a definition of the attached files without path
type AttachedFile struct {
@@ -52,8 +97,7 @@ type Message struct {
}
// SendEmail implements alertingReceivers.EmailSender.
-func (s *Sender) SendEmail(ctx context.Context, cmd *alertingReceivers.SendEmailSettings) error {
- fmt.Println("SendEmail() called!")
+func (s *defaultEmailSender) SendEmail(ctx context.Context, cmd *SendEmailSettings) error {
var attached []*AttachedFile
if cmd.AttachedFiles != nil {
attached = make([]*AttachedFile, 0, len(cmd.AttachedFiles))
@@ -78,7 +122,7 @@ func (s *Sender) SendEmail(ctx context.Context, cmd *alertingReceivers.SendEmail
})
}
-func (s *Sender) SendEmailCommandHandlerSync(ctx context.Context, cmd *SendEmailCommand) error {
+func (s *defaultEmailSender) SendEmailCommandHandlerSync(ctx context.Context, cmd *SendEmailCommand) error {
message, err := s.buildEmailMessage(&SendEmailCommand{
Data: cmd.Data,
Info: cmd.Info,
@@ -99,16 +143,16 @@ func (s *Sender) SendEmailCommandHandlerSync(ctx context.Context, cmd *SendEmail
return err
}
-func (s *Sender) buildEmailMessage(cmd *SendEmailCommand) (*Message, error) {
+func (s *defaultEmailSender) buildEmailMessage(cmd *SendEmailCommand) (*Message, error) {
data := cmd.Data
if data == nil {
data = make(map[string]any, 10)
}
- setDefaultTemplateData(s.smtp.ExternalURL, data)
+ s.setDefaultTemplateData(data)
var buffer bytes.Buffer
- if err := mailTemplates.ExecuteTemplate(&buffer, cmd.Template, data); err != nil {
+ if err := s.tmpl.ExecuteTemplate(&buffer, cmd.Template, data); err != nil {
return nil, err
}
@@ -141,7 +185,7 @@ func (s *Sender) buildEmailMessage(cmd *SendEmailCommand) (*Message, error) {
}
}
- addr := mail.Address{Name: s.smtp.FromName, Address: s.smtp.FromAddress}
+ addr := mail.Address{Name: s.cfg.FromName, Address: s.cfg.FromAddress}
return &Message{
To: cmd.To,
SingleEmail: cmd.SingleEmail,
@@ -154,9 +198,9 @@ func (s *Sender) buildEmailMessage(cmd *SendEmailCommand) (*Message, error) {
}, nil
}
-func setDefaultTemplateData(externalURL string, data map[string]any) {
- data["AppUrl"] = externalURL
- data["BuildVersion"] = version.Version
+func (s *defaultEmailSender) setDefaultTemplateData(data map[string]any) {
+ data["AppUrl"] = s.cfg.ExternalURL
+ data["BuildVersion"] = s.cfg.Version
data["Subject"] = map[string]any{}
dataCopy := map[string]any{}
for k, v := range data {
@@ -165,7 +209,7 @@ func setDefaultTemplateData(externalURL string, data map[string]any) {
data["TemplateData"] = dataCopy
}
-func (s *Sender) Send(ctx context.Context, messages ...*Message) (int, error) {
+func (s *defaultEmailSender) Send(ctx context.Context, messages ...*Message) (int, error) {
// TODO: add
// ctx, span := tracer.Start(ctx, "notifications.SmtpClient.Send",
// trace.WithAttributes(attribute.Int("messages", len(messages))),
@@ -209,8 +253,8 @@ func (s *Sender) Send(ctx context.Context, messages ...*Message) (int, error) {
return sentEmailsCount, err
}
-func (s *Sender) createDialer() (*gomail.Dialer, error) {
- host, port, err := net.SplitHostPort(s.smtp.Host)
+func (s *defaultEmailSender) createDialer() (*gomail.Dialer, error) {
+ host, port, err := net.SplitHostPort(s.cfg.Host)
if err != nil {
return nil, err
}
@@ -220,30 +264,30 @@ func (s *Sender) createDialer() (*gomail.Dialer, error) {
}
tlsconfig := &tls.Config{
- InsecureSkipVerify: s.smtp.SkipVerify,
+ InsecureSkipVerify: s.cfg.SkipVerify,
ServerName: host,
}
- if s.smtp.CertFile != "" {
- cert, err := tls.LoadX509KeyPair(s.smtp.CertFile, s.smtp.KeyFile)
+ if s.cfg.CertFile != "" {
+ cert, err := tls.LoadX509KeyPair(s.cfg.CertFile, s.cfg.KeyFile)
if err != nil {
return nil, fmt.Errorf("could not load cert or key file: %w", err)
}
tlsconfig.Certificates = []tls.Certificate{cert}
}
- d := gomail.NewDialer(host, iPort, s.smtp.AuthUser, s.smtp.AuthPassword)
+ d := gomail.NewDialer(host, iPort, s.cfg.AuthUser, s.cfg.AuthPassword)
d.TLSConfig = tlsconfig
- d.LocalName = s.smtp.EhloIdentity
+ d.LocalName = s.cfg.EhloIdentity
return d, nil
}
// buildEmail converts the Message DTO to a gomail message.
-func (s *Sender) buildEmail(ctx context.Context, msg *Message) *gomail.Message {
+func (s *defaultEmailSender) buildEmail(ctx context.Context, msg *Message) *gomail.Message {
m := gomail.NewMessage()
// add all static headers to the email message
- for h, val := range s.smtp.StaticHeaders {
+ for h, val := range s.cfg.StaticHeaders {
m.SetHeader(h, val)
}
m.SetHeader("From", msg.From)
@@ -280,3 +324,43 @@ func setFiles(
}))
}
}
+
+// hiddenSubjectTemplateFunc sets the subject template (value) on the map represented by `.Subject.` (obj) so that it can be compiled and executed later.
+// It returns a blank string, so there will be no resulting value left in place of the template.
+func hiddenSubjectTemplateFunc(obj map[string]any, value string) string {
+ obj["value"] = value
+ return ""
+}
+
+// subjectTemplateFunc does the same thing has hiddenSubjectTemplateFunc, but in addition it executes and returns the subject template using the data represented in `.TemplateData` (data)
+// This results in the template being replaced by the subject string.
+func subjectTemplateFunc(obj map[string]any, data map[string]any, value string) string {
+ obj["value"] = value
+
+ titleTmpl, err := template.New("title").Parse(value)
+ if err != nil {
+ return ""
+ }
+
+ var buf bytes.Buffer
+ err = titleTmpl.ExecuteTemplate(&buf, "title", data)
+ if err != nil {
+ return ""
+ }
+
+ subj := buf.String()
+ // Since we have already executed the template, save it to subject data so we don't have to do it again later on
+ obj["executed_template"] = subj
+ return subj
+}
+
+// __dangerouslyInjectHTML allows marking areas of am email template as HTML safe, this will _not_ sanitize the string and will allow HTML snippets to be rendered verbatim.
+// Use with absolute care as this _could_ allow for XSS attacks when used in an insecure context.
+//
+// It's safe to ignore gosec warning G203 when calling this function in an HTML template because we assume anyone who has write access
+// to the email templates folder is an administrator.
+//
+// nolint:gosec
+func __dangerouslyInjectHTML(s string) template.HTML {
+ return template.HTML(s)
+}
diff --git a/vendor/github.com/grafana/alerting/receivers/templates/ng_alert_notification.html b/vendor/github.com/grafana/alerting/receivers/templates/ng_alert_notification.html
new file mode 100644
index 00000000000..43fabdb6787
--- /dev/null
+++ b/vendor/github.com/grafana/alerting/receivers/templates/ng_alert_notification.html
@@ -0,0 +1,1279 @@
+
+
+
+
+
+ {{ Subject .Subject .TemplateData "{{ .Title }}" }}
+
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ __dangerouslyInjectHTML `` }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+ {{ $numberOfFiringInstance := (len .Alerts.Firing) }}
+ {{ $numberOfResolvedAlerts := (len .Alerts.Resolved) }}
+
+
+
+
+
+ {{ if $numberOfFiringInstance }}
+
+ {{ $numberOfFiringInstance }} firing alert {{ $numberOfFiringInstance| plural "instance" "instances" }}
+
+ {{ end }}
+
+
+ {{ if and $numberOfFiringInstance $numberOfResolvedAlerts }}
+ and
+ {{ end }}
+
+
+ {{ if $numberOfResolvedAlerts }}
+
+ {{ $numberOfResolvedAlerts }} resolved alert {{ $numberOfResolvedAlerts| plural "instance" "instances" }}
+
+ {{ end }}
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+ {{ if eq (.GroupLabels.SortedPairs.Names | join ",") "alertname,grafana_folder" }}
+
+
+
+ 📁 {{ .GroupLabels.grafana_folder }} › {{ .GroupLabels.alertname }}
+
+ |
+
+ {{ else if gt (len .GroupLabels.SortedPairs) 0 }}
+
+
+
+ 📁 Grouped by
+
+ {{ range .GroupLabels.SortedPairs }}
+
+ {{ .Name }}={{ .Value }}
+
+ {{ end }}
+
+
+ |
+
+ {{ end }}
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ if .Message }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+
+
+ {{ range $line := (splitList "\n" .Message) }}
+
+ {{ $line }}
+
+ {{ end }}
+
+
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ else }}{{ if .Alerts.Firing }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+
+ 🔥 {{ .Alerts.Firing | len }} firing instances
+
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ range .Alerts.Firing }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ .Labels.alertname }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ if gt (len .GeneratorURL) 0 }}
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ if .ImageURL }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}{{ if .EmbeddedImage }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+ {{ if .Annotations.summary }}
+
+
+ Summary
+ |
+
+
+
+ {{- .Annotations.summary -}}
+ |
+
+ {{ end }}{{ if .Annotations.description }}
+
+
+ Description
+ |
+
+
+
+
+ {{ range $line := (splitList "\n" .Annotations.description) }}
+ {{ $line }}
+ {{ end }}
+
+ |
+
+ {{ end }}
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ if .Values }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+
+
+
+
+
+ {{ range $refID, $value := .Values }}
+ {{ $refID }}={{ $value }} {{ end }}
+
+ |
+
+
+
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+ {{ if .Labels.SortedPairs }}
+
+
+ Labels
+ |
+
+
+
+
+ {{ range .Labels.SortedPairs }}
+
+
+ {{ .Name }}
+ |
+ {{ .Value }} |
+
+ {{ end }}
+
+ |
+
+ {{ end }}{{ if (without .Annotations.SortedPairs.Names "description" "summary") }}
+
+
+ Annotations
+ |
+
+
+
+
+ {{ range .Annotations.SortedPairs }}
+ {{ if and (ne .Name "description") (ne .Name "summary") }}
+
+
+ {{ .Name }}
+ |
+ {{ .Value }} |
+
+ {{ end }}
+ {{ end }}
+
+ |
+
+ {{ end }}
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ if .SilenceURL }}
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}{{ if .Annotations.runbook_url }}
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}{{ if .DashboardURL }}
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}{{ if .PanelURL }}
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ Observed {{ ago .StartsAt }} before this notification was delivered, at {{ .StartsAt }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}{{ end }}{{ if .Alerts.Resolved }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+
+ ✅ {{ .Alerts.Resolved | len }} resolved instances
+
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ range .Alerts.Resolved }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ .Labels.alertname }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ if gt (len .GeneratorURL) 0 }}
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ if .ImageURL }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}{{ if .EmbeddedImage }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+ {{ if .Annotations.summary }}
+
+
+ Summary
+ |
+
+
+
+ {{- .Annotations.summary -}}
+ |
+
+ {{ end }}{{ if .Annotations.description }}
+
+
+ Description
+ |
+
+
+
+
+ {{ range $line := (splitList "\n" .Annotations.description) }}
+ {{ $line }}
+ {{ end }}
+
+ |
+
+ {{ end }}
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ if .Values }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+
+
+
+
+
+ {{ range $refID, $value := .Values }}
+ {{ $refID }}={{ $value }} {{ end }}
+
+ |
+
+
+
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+ {{ if .Labels.SortedPairs }}
+
+
+ Labels
+ |
+
+
+
+
+ {{ range .Labels.SortedPairs }}
+
+
+ {{ .Name }}
+ |
+ {{ .Value }} |
+
+ {{ end }}
+
+ |
+
+ {{ end }}{{ if (without .Annotations.SortedPairs.Names "description" "summary") }}
+
+
+ Annotations
+ |
+
+
+
+
+ {{ range .Annotations.SortedPairs }}
+ {{ if and (ne .Name "description") (ne .Name "summary") }}
+
+
+ {{ .Name }}
+ |
+ {{ .Value }} |
+
+ {{ end }}
+ {{ end }}
+
+ |
+
+ {{ end }}
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ if .SilenceURL }}
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}{{ if .Annotations.runbook_url }}
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}{{ if .DashboardURL }}
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}{{ if .PanelURL }}
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ Observed {{ ago .StartsAt }} before this notification was delivered, at {{ .StartsAt }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+ {{ end }}{{ end }}{{ end }}
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+ {{ __dangerouslyInjectHTML `` }}
+ |
+
+
+
+
+ {{ __dangerouslyInjectHTML `` }}
+
+
+
+
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 3667ff3e0e8..7e303e1c51b 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -577,7 +577,7 @@ github.com/gosimple/slug
# github.com/grafana-tools/sdk v0.0.0-20220919052116-6562121319fc
## explicit; go 1.13
github.com/grafana-tools/sdk
-# github.com/grafana/alerting v0.0.0-20240607182251-835aff588914
+# github.com/grafana/alerting v0.0.0-20240618145205-cdfc0e849e0b
## explicit; go 1.21
github.com/grafana/alerting/cluster
github.com/grafana/alerting/definition