diff --git a/logging/log.go b/logging/log.go index 36402d5d..9b852bad 100644 --- a/logging/log.go +++ b/logging/log.go @@ -1,6 +1,6 @@ package logging -type LoggerFactory func(ctx ...interface{}) Logger +type LoggerFactory func(loggerName string, ctx ...interface{}) Logger type Logger interface { // New returns a new contextual Logger that has this logger's context plus the given context. diff --git a/notify/factory.go b/notify/factory.go index 659e4132..f1ed9e91 100644 --- a/notify/factory.go +++ b/notify/factory.go @@ -1,10 +1,14 @@ package notify import ( - "strings" + "fmt" "github.com/prometheus/alertmanager/notify" + "github.com/prometheus/alertmanager/template" + "github.com/prometheus/alertmanager/types" + "github.com/grafana/alerting/images" + "github.com/grafana/alerting/logging" "github.com/grafana/alerting/receivers" "github.com/grafana/alerting/receivers/alertmanager" "github.com/grafana/alerting/receivers/dinding" @@ -27,57 +31,107 @@ import ( "github.com/grafana/alerting/receivers/wecom" ) -var receiverFactories = map[string]func(receivers.FactoryConfig) (NotificationChannel, error){ - "prometheus-alertmanager": wrap(alertmanager.New), - "dingding": wrap(dinding.New), - "discord": wrap(discord.New), - "email": wrap(email.New), - "googlechat": wrap(googlechat.New), - "kafka": wrap(kafka.New), - "line": wrap(line.New), - "opsgenie": wrap(opsgenie.New), - "pagerduty": wrap(pagerduty.New), - "pushover": wrap(pushover.New), - "sensugo": wrap(sensugo.New), - "slack": wrap(slack.New), - "teams": wrap(teams.New), - "telegram": wrap(telegram.New), - "threema": wrap(threema.New), - "victorops": wrap(victorops.New), - "webhook": wrap(webhook.New), - "wecom": wrap(wecom.New), - "webex": wrap(webex.New), -} - -type NotificationChannel interface { - notify.Notifier - notify.ResolvedSender -} - -func Factory(receiverType string) (func(receivers.FactoryConfig) (NotificationChannel, error), bool) { - receiverType = strings.ToLower(receiverType) - factory, exists := receiverFactories[receiverType] - return factory, exists -} - -// wrap wraps the notifier's factory errors with receivers.ReceiverValidationError -func wrap[T NotificationChannel](f func(fc receivers.FactoryConfig) (T, error)) func(receivers.FactoryConfig) (NotificationChannel, error) { - return func(fc receivers.FactoryConfig) (NotificationChannel, error) { - ch, err := f(fc) - if err != nil { - return nil, ReceiverValidationError{ - Err: err, - // TODO it will be removed in the next PR - Cfg: &GrafanaReceiver{ - UID: fc.Config.UID, - Name: fc.Config.Name, - Type: fc.Config.Type, - DisableResolveMessage: fc.Config.DisableResolveMessage, - Settings: fc.Config.Settings, - SecureSettings: nil, - }, +// BuildReceiverIntegrations creates integrations for each configured notification channel in GrafanaReceiverConfig. +// It returns a slice of Integration objects, one for each notification channel, along with any errors that occurred. +func BuildReceiverIntegrations( + receiver GrafanaReceiverConfig, + tmpl *template.Template, + img images.ImageStore, + logger logging.LoggerFactory, + newWebhookSender func(n receivers.Metadata) (receivers.WebhookSender, error), + newEmailSender func(n receivers.Metadata) (receivers.EmailSender, error), + orgID int64, + version string, +) ([]*Integration, error) { + type notificationChannel interface { + notify.Notifier + notify.ResolvedSender + } + var ( + integrations []*Integration + errors types.MultiError + nl = func(meta receivers.Metadata) logging.Logger { + return logger("ngalert.notifier."+meta.Type, "notifierUID", meta.UID) + } + ci = func(idx int, cfg receivers.Metadata, n notificationChannel) { + i := NewIntegration(n, n, cfg.Type, idx) + integrations = append(integrations, i) + } + nw = func(cfg receivers.Metadata) receivers.WebhookSender { + w, e := newWebhookSender(cfg) + if e != nil { + errors.Add(fmt.Errorf("unable to build webhook client for %s notifier %s (UID: %s): %w ", cfg.Type, cfg.Name, cfg.UID, e)) + return nil // return nil to simplify the construction code. This works because constructor in notifiers do not check the argument for nil. + // This does not cause misconfigured notifiers because it populates `errors`, which causes the function to return nil integrations and non-nil error. } + return w } - return ch, nil + ) + // Range through each notification channel in the receiver and create an integration for it. + for i, cfg := range receiver.AlertmanagerConfigs { + ci(i, cfg.Metadata, alertmanager.New(cfg.Settings, cfg.Metadata, img, nl(cfg.Metadata))) + } + for i, cfg := range receiver.DingdingConfigs { + ci(i, cfg.Metadata, dinding.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), nl(cfg.Metadata))) + } + for i, cfg := range receiver.DiscordConfigs { + ci(i, cfg.Metadata, discord.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), img, nl(cfg.Metadata), version)) + } + for i, cfg := range receiver.EmailConfigs { + mailCli, e := newEmailSender(cfg.Metadata) + if e != nil { + errors.Add(fmt.Errorf("unable to build email client for %s notifier %s (UID: %s): %w ", cfg.Type, cfg.Name, cfg.UID, e)) + continue + } + ci(i, cfg.Metadata, email.New(cfg.Settings, cfg.Metadata, tmpl, mailCli, img, nl(cfg.Metadata))) + } + for i, cfg := range receiver.GooglechatConfigs { + ci(i, cfg.Metadata, googlechat.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), img, nl(cfg.Metadata), version)) + } + for i, cfg := range receiver.KafkaConfigs { + ci(i, cfg.Metadata, kafka.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), img, nl(cfg.Metadata))) + } + for i, cfg := range receiver.LineConfigs { + ci(i, cfg.Metadata, line.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), nl(cfg.Metadata))) + } + for i, cfg := range receiver.OpsgenieConfigs { + ci(i, cfg.Metadata, opsgenie.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), img, nl(cfg.Metadata))) + } + for i, cfg := range receiver.PagerdutyConfigs { + ci(i, cfg.Metadata, pagerduty.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), img, nl(cfg.Metadata))) + } + for i, cfg := range receiver.PushoverConfigs { + ci(i, cfg.Metadata, pushover.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), img, nl(cfg.Metadata))) + } + for i, cfg := range receiver.SensugoConfigs { + ci(i, cfg.Metadata, sensugo.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), img, nl(cfg.Metadata))) + } + for i, cfg := range receiver.SlackConfigs { + ci(i, cfg.Metadata, slack.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), img, nl(cfg.Metadata), version)) + } + for i, cfg := range receiver.TeamsConfigs { + ci(i, cfg.Metadata, teams.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), img, nl(cfg.Metadata))) + } + for i, cfg := range receiver.TelegramConfigs { + ci(i, cfg.Metadata, telegram.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), img, nl(cfg.Metadata))) + } + for i, cfg := range receiver.ThreemaConfigs { + ci(i, cfg.Metadata, threema.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), img, nl(cfg.Metadata))) + } + for i, cfg := range receiver.VictoropsConfigs { + ci(i, cfg.Metadata, victorops.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), img, nl(cfg.Metadata), version)) + } + for i, cfg := range receiver.WebhookConfigs { + ci(i, cfg.Metadata, webhook.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), img, nl(cfg.Metadata), orgID)) + } + for i, cfg := range receiver.WecomConfigs { + ci(i, cfg.Metadata, wecom.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), nl(cfg.Metadata))) + } + for i, cfg := range receiver.WebexConfigs { + ci(i, cfg.Metadata, webex.New(cfg.Settings, cfg.Metadata, tmpl, nw(cfg.Metadata), img, nl(cfg.Metadata), orgID)) + } + if errors.Len() > 0 { + return nil, &errors } + return integrations, nil } diff --git a/notify/factory_test.go b/notify/factory_test.go new file mode 100644 index 00000000..99605ca3 --- /dev/null +++ b/notify/factory_test.go @@ -0,0 +1,118 @@ +package notify + +import ( + "context" + "errors" + "fmt" + "math/rand" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/grafana/alerting/images" + "github.com/grafana/alerting/logging" + "github.com/grafana/alerting/receivers" + "github.com/grafana/alerting/templates" +) + +func TestBuildReceiverIntegrations(t *testing.T) { + var orgID = rand.Int63() + var version = fmt.Sprintf("Grafana v%d", rand.Uint32()) + imageStore := &images.FakeImageStore{} + tmpl := templates.ForTests(t) + + webhookFactory := func(n receivers.Metadata) (receivers.WebhookSender, error) { + return receivers.MockNotificationService(), nil + } + emailFactory := func(n receivers.Metadata) (receivers.EmailSender, error) { + return receivers.MockNotificationService(), nil + } + loggerFactory := func(_ string, _ ...interface{}) logging.Logger { + return &logging.FakeLogger{} + } + + getFullConfig := func(t *testing.T) (GrafanaReceiverConfig, int) { + recCfg := &APIReceiver{ConfigReceiver: ConfigReceiver{Name: "test-receiver"}} + for notifierType, cfg := range allKnownConfigs { + recCfg.Receivers = append(recCfg.Receivers, cfg.getRawNotifierConfig(notifierType)) + } + parsed, err := BuildReceiverConfiguration(context.Background(), recCfg, GetDecryptedValueFnForTesting) + require.NoError(t, err) + return parsed, len(recCfg.Receivers) + } + + t.Run("should build all supported notifiers", func(t *testing.T) { + fullCfg, qty := getFullConfig(t) + + loggerNames := make(map[string]struct{}, qty) + logger := func(name string, _ ...interface{}) logging.Logger { + loggerNames[name] = struct{}{} + return &logging.FakeLogger{} + } + + webhooks := make(map[receivers.Metadata]struct{}, qty) + wh := func(n receivers.Metadata) (receivers.WebhookSender, error) { + webhooks[n] = struct{}{} + return webhookFactory(n) + } + + emails := make(map[receivers.Metadata]struct{}, qty) + em := func(n receivers.Metadata) (receivers.EmailSender, error) { + emails[n] = struct{}{} + return emailFactory(n) + } + + integrations, err := BuildReceiverIntegrations(fullCfg, tmpl, imageStore, logger, wh, em, orgID, version) + + require.NoError(t, err) + require.Len(t, integrations, qty) + + t.Run("should call logger factory for each config", func(t *testing.T) { + require.Len(t, loggerNames, qty) + }) + t.Run("should call webhook factory for each config that needs it", func(t *testing.T) { + require.Len(t, webhooks, 17) // we have 17 notifiers that support webhook + }) + t.Run("should call email factory for each config that needs it", func(t *testing.T) { + require.Len(t, emails, 1) // we have only email notifier that needs sender + }) + }) + t.Run("should return errors if webhook factory fails", func(t *testing.T) { + fullCfg, _ := getFullConfig(t) + calls := 0 + failingFactory := func(n receivers.Metadata) (receivers.WebhookSender, error) { + calls++ + return nil, errors.New("bad-test") + } + + integrations, err := BuildReceiverIntegrations(fullCfg, tmpl, imageStore, loggerFactory, failingFactory, emailFactory, orgID, version) + + require.Empty(t, integrations) + require.NotNil(t, err) + require.ErrorContains(t, err, "bad-test") + require.Greater(t, calls, 0) + }) + t.Run("should return errors if email factory fails", func(t *testing.T) { + fullCfg, _ := getFullConfig(t) + calls := 0 + failingFactory := func(n receivers.Metadata) (receivers.EmailSender, error) { + calls++ + return nil, errors.New("bad-test") + } + + integrations, err := BuildReceiverIntegrations(fullCfg, tmpl, imageStore, loggerFactory, webhookFactory, failingFactory, orgID, version) + + require.Empty(t, integrations) + require.NotNil(t, err) + require.ErrorContains(t, err, "bad-test") + require.Greater(t, calls, 0) + }) + t.Run("should not produce any integration if config is empty", func(t *testing.T) { + cfg := GrafanaReceiverConfig{Name: "test"} + + integrations, err := BuildReceiverIntegrations(cfg, tmpl, imageStore, loggerFactory, webhookFactory, emailFactory, orgID, version) + + require.NoError(t, err) + require.Empty(t, integrations) + }) +} diff --git a/notify/receivers.go b/notify/receivers.go index e116b548..d5c31804 100644 --- a/notify/receivers.go +++ b/notify/receivers.go @@ -347,8 +347,12 @@ type NotifierConfig[T interface{}] struct { Settings T } +// GetDecryptedValueFn is a function that returns the decrypted value of +// the given key. If the key is not present, then it returns the fallback value. +type GetDecryptedValueFn func(ctx context.Context, sjd map[string][]byte, key string, fallback string) string + // BuildReceiverConfiguration parses, decrypts and validates the APIReceiver. -func BuildReceiverConfiguration(ctx context.Context, api *APIReceiver, decrypt receivers.GetDecryptedValueFn) (GrafanaReceiverConfig, error) { +func BuildReceiverConfiguration(ctx context.Context, api *APIReceiver, decrypt GetDecryptedValueFn) (GrafanaReceiverConfig, error) { result := GrafanaReceiverConfig{ Name: api.Name, } @@ -365,7 +369,7 @@ func BuildReceiverConfiguration(ctx context.Context, api *APIReceiver, decrypt r } // parseNotifier parses receivers and populates the corresponding field in GrafanaReceiverConfig. Returns an error if the configuration cannot be parsed. -func parseNotifier(ctx context.Context, result *GrafanaReceiverConfig, receiver *GrafanaReceiver, decrypt receivers.GetDecryptedValueFn) error { +func parseNotifier(ctx context.Context, result *GrafanaReceiverConfig, receiver *GrafanaReceiver, decrypt GetDecryptedValueFn) error { secureSettings, err := decodeSecretsFromBase64(receiver.SecureSettings) if err != nil { return err diff --git a/notify/receivers_test.go b/notify/receivers_test.go index 09349498..8a9b1a00 100644 --- a/notify/receivers_test.go +++ b/notify/receivers_test.go @@ -106,14 +106,7 @@ func TestProcessNotifierError(t *testing.T) { } func TestBuildReceiverConfiguration(t *testing.T) { - var decrypt receivers.GetDecryptedValueFn = func(ctx context.Context, sjd map[string][]byte, key string, fallback string) string { - v, ok := sjd[key] - if !ok { - return fallback - } - return string(v) - } - + decrypt := GetDecryptedValueFnForTesting t.Run("should decode secrets from base64", func(t *testing.T) { recCfg := &APIReceiver{ConfigReceiver: ConfigReceiver{Name: "test-receiver"}} for notifierType, cfg := range allKnownConfigs { diff --git a/notify/testing.go b/notify/testing.go index be5fa218..e64d64ac 100644 --- a/notify/testing.go +++ b/notify/testing.go @@ -6,6 +6,8 @@ import ( "time" "github.com/prometheus/alertmanager/types" + + receiversTesting "github.com/grafana/alerting/receivers/testing" ) func newFakeMaintanenceOptions(t *testing.T) *fakeMaintenanceOptions { @@ -84,3 +86,7 @@ func (f *fakeNotifier) Notify(_ context.Context, _ ...*types.Alert) (bool, error func (f *fakeNotifier) SendResolved() bool { return true } + +func GetDecryptedValueFnForTesting(_ context.Context, sjd map[string][]byte, key string, fallback string) string { + return receiversTesting.DecryptForTesting(sjd)(key, fallback) +} diff --git a/receivers/alertmanager/alertmanager.go b/receivers/alertmanager/alertmanager.go index cd363a60..901b1f16 100644 --- a/receivers/alertmanager/alertmanager.go +++ b/receivers/alertmanager/alertmanager.go @@ -13,18 +13,13 @@ import ( "github.com/grafana/alerting/receivers" ) -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings, fc.Decrypt) - if err != nil { - return nil, err - } - +func New(cfg Config, meta receivers.Metadata, images images.ImageStore, logger logging.Logger) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - images: fc.ImageStore, - settings: settings, - logger: fc.Logger, - }, nil + Base: receivers.NewBase(meta), + images: images, + settings: cfg, + logger: logger, + } } // Notifier sends alert notifications to the alert manager diff --git a/receivers/base.go b/receivers/base.go index de0e8c85..1641b20e 100644 --- a/receivers/base.go +++ b/receivers/base.go @@ -12,7 +12,15 @@ func (n *Base) GetDisableResolveMessage() bool { return n.DisableResolveMessage } -func NewBase(cfg *NotificationChannelConfig) *Base { +// Metadata contains the metadata of the notifier. +type Metadata struct { + UID string + Name string + Type string + DisableResolveMessage bool +} + +func NewBase(cfg Metadata) *Base { return &Base{ UID: cfg.UID, Name: cfg.Name, diff --git a/receivers/config_util.go b/receivers/config_util.go index 8d17f09d..678192ce 100644 --- a/receivers/config_util.go +++ b/receivers/config_util.go @@ -7,6 +7,8 @@ import ( "gopkg.in/yaml.v3" ) +type DecryptFunc func(key string, fallback string) string + type CommaSeparatedStrings []string func (r *CommaSeparatedStrings) UnmarshalJSON(b []byte) error { diff --git a/receivers/dinding/dingding.go b/receivers/dinding/dingding.go index 0cc5bcf0..fe5edd46 100644 --- a/receivers/dinding/dingding.go +++ b/receivers/dinding/dingding.go @@ -23,19 +23,14 @@ type Notifier struct { settings Config } -// New is the constructor for the Dingding notifier -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings) - if err != nil { - return nil, err - } +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, logger logging.Logger) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - log: fc.Logger, - ns: fc.NotificationService, - tmpl: fc.Template, - settings: settings, - }, nil + Base: receivers.NewBase(meta), + log: logger, + ns: sender, + tmpl: template, + settings: cfg, + } } // Notify sends the alert notification to dingding. diff --git a/receivers/discord/discord.go b/receivers/discord/discord.go index 31b133b1..cfbb78b2 100644 --- a/receivers/discord/discord.go +++ b/receivers/discord/discord.go @@ -82,20 +82,16 @@ type discordAttachment struct { state model.AlertStatus } -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings) - if err != nil { - return nil, err - } +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, images images.ImageStore, logger logging.Logger, appVersion string) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - log: fc.Logger, - ns: fc.NotificationService, - images: fc.ImageStore, - tmpl: fc.Template, - settings: settings, - appVersion: fc.GrafanaBuildVersion, - }, nil + Base: receivers.NewBase(meta), + log: logger, + ns: sender, + images: images, + tmpl: template, + settings: cfg, + appVersion: appVersion, + } } func (d Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { diff --git a/receivers/email/email.go b/receivers/email/email.go index 5202aa26..be3e12aa 100644 --- a/receivers/email/email.go +++ b/receivers/email/email.go @@ -27,19 +27,15 @@ type Notifier struct { settings Config } -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings) - if err != nil { - return nil, err - } +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.EmailSender, images images.ImageStore, logger logging.Logger) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - log: fc.Logger, - ns: fc.NotificationService, - images: fc.ImageStore, - tmpl: fc.Template, - settings: settings, - }, nil + Base: receivers.NewBase(meta), + log: logger, + ns: sender, + images: images, + tmpl: template, + settings: cfg, + } } // Notify sends the alert notification. diff --git a/receivers/factory.go b/receivers/factory.go deleted file mode 100644 index 43cf9e82..00000000 --- a/receivers/factory.go +++ /dev/null @@ -1,82 +0,0 @@ -package receivers - -import ( - "context" - "encoding/json" - "errors" - - "github.com/prometheus/alertmanager/template" - - "github.com/grafana/alerting/images" - "github.com/grafana/alerting/logging" -) - -// GetDecryptedValueFn is a function that returns the decrypted value of -// the given key. If the key is not present, then it returns the fallback value. -type GetDecryptedValueFn func(ctx context.Context, sjd map[string][]byte, key string, fallback string) string - -type DecryptFunc func(key string, fallback string) string - -type NotificationSender interface { - WebhookSender - EmailSender -} - -type NotificationChannelConfig struct { - OrgID int64 // only used internally - UID string `json:"uid"` - Name string `json:"name"` - Type string `json:"type"` - DisableResolveMessage bool `json:"disableResolveMessage"` - Settings json.RawMessage `json:"settings"` - SecureSettings map[string][]byte `json:"secureSettings"` -} - -// Metadata contains the metadata of the notifier. -type Metadata struct { - UID string - Name string - Type string - DisableResolveMessage bool -} - -type FactoryConfig struct { - Config *NotificationChannelConfig - // Used by some receivers to include as part of the source - GrafanaBuildVersion string - NotificationService NotificationSender - DecryptFunc GetDecryptedValueFn - ImageStore images.ImageStore - // Used to retrieve image URLs for messages, or data for uploads. - Template *template.Template - Logger logging.Logger -} - -func (fc *FactoryConfig) Decrypt(key, fallback string) string { - return fc.DecryptFunc(context.Background(), fc.Config.SecureSettings, key, fallback) -} - -func NewFactoryConfig(config *NotificationChannelConfig, notificationService NotificationSender, - decryptFunc GetDecryptedValueFn, template *template.Template, imageStore images.ImageStore, loggerFactory logging.LoggerFactory, buildVersion string) (FactoryConfig, error) { - if config.Settings == nil { - return FactoryConfig{}, errors.New("no settings supplied") - } - // not all receivers do need secure settings, we still might interact with - // them, so we make sure they are never nil - if config.SecureSettings == nil { - config.SecureSettings = map[string][]byte{} - } - - if imageStore == nil { - imageStore = &images.UnavailableImageStore{} - } - return FactoryConfig{ - Config: config, - NotificationService: notificationService, - GrafanaBuildVersion: buildVersion, - DecryptFunc: decryptFunc, - Template: template, - ImageStore: imageStore, - Logger: loggerFactory("ngalert.notifier." + config.Type), - }, nil -} diff --git a/receivers/googlechat/googlechat.go b/receivers/googlechat/googlechat.go index c2e19ec9..82b380bb 100644 --- a/receivers/googlechat/googlechat.go +++ b/receivers/googlechat/googlechat.go @@ -33,20 +33,16 @@ var ( timeNow = time.Now ) -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings) - if err != nil { - return nil, err - } +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, images images.ImageStore, logger logging.Logger, appVersion string) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - log: fc.Logger, - ns: fc.NotificationService, - images: fc.ImageStore, - tmpl: fc.Template, - settings: settings, - appVersion: fc.GrafanaBuildVersion, - }, nil + Base: receivers.NewBase(meta), + log: logger, + ns: sender, + images: images, + tmpl: template, + settings: cfg, + appVersion: appVersion, + } } // Notify send an alert notification to Google Chat. diff --git a/receivers/kafka/kafka.go b/receivers/kafka/kafka.go index 82c29cc8..46f8034f 100644 --- a/receivers/kafka/kafka.go +++ b/receivers/kafka/kafka.go @@ -55,21 +55,15 @@ type Notifier struct { settings Config } -// New is the constructor function for the Kafka notifier. -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings, fc.Decrypt) - if err != nil { - return nil, err - } - +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, images images.ImageStore, logger logging.Logger) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - log: fc.Logger, - images: fc.ImageStore, - ns: fc.NotificationService, - tmpl: fc.Template, - settings: settings, - }, nil + Base: receivers.NewBase(meta), + log: logger, + ns: sender, + images: images, + tmpl: template, + settings: cfg, + } } // Notify sends the alert notification. diff --git a/receivers/line/line.go b/receivers/line/line.go index 5259a52e..e6ef6cfc 100644 --- a/receivers/line/line.go +++ b/receivers/line/line.go @@ -29,20 +29,14 @@ type Notifier struct { settings Config } -// New is the constructor for the LINE notifier -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings, fc.Decrypt) - if err != nil { - return nil, err - } - +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, logger logging.Logger) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - log: fc.Logger, - ns: fc.NotificationService, - tmpl: fc.Template, - settings: settings, - }, nil + Base: receivers.NewBase(meta), + log: logger, + ns: sender, + tmpl: template, + settings: cfg, + } } // Notify send an alert notification to LINE diff --git a/receivers/opsgenie/opsgenie.go b/receivers/opsgenie/opsgenie.go index 4c58060c..3e279b14 100644 --- a/receivers/opsgenie/opsgenie.go +++ b/receivers/opsgenie/opsgenie.go @@ -38,20 +38,15 @@ type Notifier struct { settings Config } -// New is the constructor for the Opsgenie notifier -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings, fc.Decrypt) - if err != nil { - return nil, err - } +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, images images.ImageStore, logger logging.Logger) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - tmpl: fc.Template, - log: fc.Logger, - ns: fc.NotificationService, - images: fc.ImageStore, - settings: settings, - }, nil + Base: receivers.NewBase(meta), + log: logger, + ns: sender, + images: images, + tmpl: template, + settings: cfg, + } } // Notify sends an alert notification to Opsgenie diff --git a/receivers/pagerduty/pagerduty.go b/receivers/pagerduty/pagerduty.go index 5e9c770e..c959d22b 100644 --- a/receivers/pagerduty/pagerduty.go +++ b/receivers/pagerduty/pagerduty.go @@ -50,20 +50,15 @@ type Notifier struct { } // New is the constructor for the PagerDuty notifier -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings, fc.Decrypt) - if err != nil { - return nil, err - } - +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, images images.ImageStore, logger logging.Logger) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - tmpl: fc.Template, - log: fc.Logger, - ns: fc.NotificationService, - images: fc.ImageStore, - settings: settings, - }, nil + Base: receivers.NewBase(meta), + log: logger, + ns: sender, + images: images, + tmpl: template, + settings: cfg, + } } // Notify sends an alert notification to PagerDuty diff --git a/receivers/pushover/pushover.go b/receivers/pushover/pushover.go index 461c9fff..541056bb 100644 --- a/receivers/pushover/pushover.go +++ b/receivers/pushover/pushover.go @@ -48,19 +48,15 @@ type Notifier struct { } // New is the constructor for the pushover notifier -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings, fc.Decrypt) - if err != nil { - return nil, err - } +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, images images.ImageStore, logger logging.Logger) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - tmpl: fc.Template, - log: fc.Logger, - images: fc.ImageStore, - ns: fc.NotificationService, - settings: settings, - }, nil + Base: receivers.NewBase(meta), + log: logger, + ns: sender, + images: images, + tmpl: template, + settings: cfg, + } } // Notify sends an alert notification to Slack. diff --git a/receivers/sensugo/sensugo.go b/receivers/sensugo/sensugo.go index e7b6d405..611019c6 100644 --- a/receivers/sensugo/sensugo.go +++ b/receivers/sensugo/sensugo.go @@ -32,19 +32,15 @@ type Notifier struct { } // New is the constructor for the SensuGo notifier -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings, fc.Decrypt) - if err != nil { - return nil, err - } +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, images images.ImageStore, logger logging.Logger) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - log: fc.Logger, - images: fc.ImageStore, - ns: fc.NotificationService, - tmpl: fc.Template, - settings: settings, - }, nil + Base: receivers.NewBase(meta), + log: logger, + images: images, + ns: sender, + tmpl: template, + settings: cfg, + } } // Notify sends an alert notification to Sensu Go diff --git a/receivers/slack/slack.go b/receivers/slack/slack.go index 2d75d24b..cfc8546a 100644 --- a/receivers/slack/slack.go +++ b/receivers/slack/slack.go @@ -90,23 +90,18 @@ func uploadURL(s Config) (string, error) { return u.String(), nil } -func New(factoryConfig receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(factoryConfig.Config.Settings, factoryConfig.Decrypt) - if err != nil { - return nil, err - } - +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, images images.ImageStore, logger logging.Logger, appVersion string) *Notifier { return &Notifier{ - Base: receivers.NewBase(factoryConfig.Config), - settings: settings, + Base: receivers.NewBase(meta), + settings: cfg, - images: factoryConfig.ImageStore, - webhookSender: factoryConfig.NotificationService, + images: images, + webhookSender: sender, sendFn: sendSlackRequest, - log: factoryConfig.Logger, - tmpl: factoryConfig.Template, - appVersion: factoryConfig.GrafanaBuildVersion, - }, nil + log: logger, + tmpl: template, + appVersion: appVersion, + } } // slackMessage is the slackMessage for sending a slack notification. diff --git a/receivers/teams/teams.go b/receivers/teams/teams.go index ad386151..acf29789 100644 --- a/receivers/teams/teams.go +++ b/receivers/teams/teams.go @@ -233,20 +233,15 @@ type Notifier struct { settings Config } -// New is the constructor for Teams notifier. -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings) - if err != nil { - return nil, err - } +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, images images.ImageStore, logger logging.Logger) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - log: fc.Logger, - ns: fc.NotificationService, - images: fc.ImageStore, - tmpl: fc.Template, - settings: settings, - }, nil + Base: receivers.NewBase(meta), + log: logger, + ns: sender, + images: images, + tmpl: template, + settings: cfg, + } } func (tn *Notifier) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { diff --git a/receivers/telegram/telegram.go b/receivers/telegram/telegram.go index 21bfd69d..fa20f61c 100644 --- a/receivers/telegram/telegram.go +++ b/receivers/telegram/telegram.go @@ -38,19 +38,15 @@ type Notifier struct { } // New is the constructor for the Telegram notifier -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings, fc.Decrypt) - if err != nil { - return nil, err - } +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, images images.ImageStore, logger logging.Logger) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - tmpl: fc.Template, - log: fc.Logger, - images: fc.ImageStore, - ns: fc.NotificationService, - settings: settings, - }, nil + Base: receivers.NewBase(meta), + tmpl: template, + log: logger, + images: images, + ns: sender, + settings: cfg, + } } // Notify send an alert notification to Telegram. diff --git a/receivers/threema/threema.go b/receivers/threema/threema.go index 3bd4ee35..8f2f3607 100644 --- a/receivers/threema/threema.go +++ b/receivers/threema/threema.go @@ -32,19 +32,15 @@ type Notifier struct { settings Config } -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings, fc.Decrypt) - if err != nil { - return nil, err - } +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, images images.ImageStore, logger logging.Logger) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - log: fc.Logger, - images: fc.ImageStore, - ns: fc.NotificationService, - tmpl: fc.Template, - settings: settings, - }, nil + Base: receivers.NewBase(meta), + log: logger, + images: images, + ns: sender, + tmpl: template, + settings: cfg, + } } // Notify send an alert notification to Threema diff --git a/receivers/victorops/victorops.go b/receivers/victorops/victorops.go index b1812cef..5da6585f 100644 --- a/receivers/victorops/victorops.go +++ b/receivers/victorops/victorops.go @@ -40,20 +40,16 @@ type Notifier struct { // New creates an instance of VictoropsNotifier that // handles posting notifications to Victorops REST API -func New(fc receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(fc.Config.Settings) - if err != nil { - return nil, err - } +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, images images.ImageStore, logger logging.Logger, appVersion string) *Notifier { return &Notifier{ - Base: receivers.NewBase(fc.Config), - log: fc.Logger, - images: fc.ImageStore, - ns: fc.NotificationService, - tmpl: fc.Template, - settings: settings, - appVersion: fc.GrafanaBuildVersion, - }, nil + Base: receivers.NewBase(meta), + log: logger, + images: images, + ns: sender, + tmpl: template, + settings: cfg, + appVersion: appVersion, + } } // Notify sends notification to Victorops via POST to URL endpoint diff --git a/receivers/webex/webex.go b/receivers/webex/webex.go index 01ae5117..a212bcd5 100644 --- a/receivers/webex/webex.go +++ b/receivers/webex/webex.go @@ -26,21 +26,16 @@ type Notifier struct { settings Config } -func New(factoryConfig receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(factoryConfig.Config.Settings, factoryConfig.Decrypt) - if err != nil { - return nil, err - } - +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, images images.ImageStore, logger logging.Logger, orgID int64) *Notifier { return &Notifier{ - Base: receivers.NewBase(factoryConfig.Config), - orgID: factoryConfig.Config.OrgID, - log: factoryConfig.Logger, - ns: factoryConfig.NotificationService, - images: factoryConfig.ImageStore, - tmpl: factoryConfig.Template, - settings: settings, - }, nil + Base: receivers.NewBase(meta), + orgID: orgID, + log: logger, + ns: sender, + images: images, + tmpl: template, + settings: cfg, + } } // webexMessage defines the JSON object to send to Webex endpoints. diff --git a/receivers/webhook/webhook.go b/receivers/webhook/webhook.go index 771375e6..62b0b0ee 100644 --- a/receivers/webhook/webhook.go +++ b/receivers/webhook/webhook.go @@ -30,20 +30,16 @@ type Notifier struct { // New is the constructor for // the WebHook notifier. -func New(factoryConfig receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(factoryConfig.Config.Settings, factoryConfig.Decrypt) - if err != nil { - return nil, err - } +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, images images.ImageStore, logger logging.Logger, orgID int64) *Notifier { return &Notifier{ - Base: receivers.NewBase(factoryConfig.Config), - orgID: factoryConfig.Config.OrgID, - log: factoryConfig.Logger, - ns: factoryConfig.NotificationService, - images: factoryConfig.ImageStore, - tmpl: factoryConfig.Template, - settings: settings, - }, nil + Base: receivers.NewBase(meta), + orgID: orgID, + log: logger, + ns: sender, + images: images, + tmpl: template, + settings: cfg, + } } // webhookMessage defines the JSON object send to webhook endpoints. diff --git a/receivers/wecom/wecom.go b/receivers/wecom/wecom.go index 2e53903e..9d4ea41b 100644 --- a/receivers/wecom/wecom.go +++ b/receivers/wecom/wecom.go @@ -28,18 +28,14 @@ type Notifier struct { group singleflight.Group } -func New(factoryConfig receivers.FactoryConfig) (*Notifier, error) { - settings, err := NewConfig(factoryConfig.Config.Settings, factoryConfig.Decrypt) - if err != nil { - return nil, err - } +func New(cfg Config, meta receivers.Metadata, template *template.Template, sender receivers.WebhookSender, logger logging.Logger) *Notifier { return &Notifier{ - Base: receivers.NewBase(factoryConfig.Config), - tmpl: factoryConfig.Template, - log: factoryConfig.Logger, - ns: factoryConfig.NotificationService, - settings: settings, - }, nil + Base: receivers.NewBase(meta), + tmpl: template, + log: logger, + ns: sender, + settings: cfg, + } } // Notify send an alert notification to WeCom.