Chore: Remove bus from the alerting service (#44496)

* propagate notificationservice down to the notifiers

* replace dispatch in result handler

* remove dispatch from the rule reader

* remove dispatch from eval context

* remove dispatch from alerting usage

* remove dispatch from alerting usage

* remove dispatch from notifier

* attempt to fix tests in alerting

* hello linter, my old friend; also disable some tests for now

* use mocks to fix the tests

* resolving wire providers

* make linter happy

* remove yet another bus.dispatch

* fix tests using store mock
richih/1643892548
Serge Zaitsev 3 years ago committed by GitHub
parent a79c048344
commit 43b15b92ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      pkg/server/wire.go
  2. 4
      pkg/services/alerting/alerting_usage.go
  3. 12
      pkg/services/alerting/alerting_usage_test.go
  4. 3
      pkg/services/alerting/conditions/query.go
  5. 9
      pkg/services/alerting/conditions/query_interval_test.go
  6. 9
      pkg/services/alerting/conditions/query_test.go
  7. 24
      pkg/services/alerting/engine.go
  8. 2
      pkg/services/alerting/engine_integration_test.go
  9. 64
      pkg/services/alerting/engine_test.go
  10. 8
      pkg/services/alerting/eval_context.go
  11. 4
      pkg/services/alerting/eval_context_test.go
  12. 28
      pkg/services/alerting/eval_handler_test.go
  13. 36
      pkg/services/alerting/notifier.go
  14. 22
      pkg/services/alerting/notifier_test.go
  15. 8
      pkg/services/alerting/notifiers/alertmanager.go
  16. 8
      pkg/services/alerting/notifiers/alertmanager_test.go
  17. 6
      pkg/services/alerting/notifiers/base.go
  18. 10
      pkg/services/alerting/notifiers/base_test.go
  19. 8
      pkg/services/alerting/notifiers/dingding.go
  20. 6
      pkg/services/alerting/notifiers/dingding_test.go
  21. 8
      pkg/services/alerting/notifiers/discord.go
  22. 4
      pkg/services/alerting/notifiers/discord_test.go
  23. 8
      pkg/services/alerting/notifiers/email.go
  24. 6
      pkg/services/alerting/notifiers/email_test.go
  25. 8
      pkg/services/alerting/notifiers/googlechat.go
  26. 4
      pkg/services/alerting/notifiers/googlechat_test.go
  27. 8
      pkg/services/alerting/notifiers/hipchat.go
  28. 6
      pkg/services/alerting/notifiers/hipchat_test.go
  29. 8
      pkg/services/alerting/notifiers/kafka.go
  30. 4
      pkg/services/alerting/notifiers/kafka_test.go
  31. 8
      pkg/services/alerting/notifiers/line.go
  32. 4
      pkg/services/alerting/notifiers/line_test.go
  33. 10
      pkg/services/alerting/notifiers/opsgenie.go
  34. 65
      pkg/services/alerting/notifiers/opsgenie_test.go
  35. 8
      pkg/services/alerting/notifiers/pagerduty.go
  36. 32
      pkg/services/alerting/notifiers/pagerduty_test.go
  37. 8
      pkg/services/alerting/notifiers/pushover.go
  38. 8
      pkg/services/alerting/notifiers/pushover_test.go
  39. 8
      pkg/services/alerting/notifiers/sensu.go
  40. 4
      pkg/services/alerting/notifiers/sensu_test.go
  41. 8
      pkg/services/alerting/notifiers/sensugo.go
  42. 4
      pkg/services/alerting/notifiers/sensugo_test.go
  43. 8
      pkg/services/alerting/notifiers/slack.go
  44. 12
      pkg/services/alerting/notifiers/slack_test.go
  45. 8
      pkg/services/alerting/notifiers/teams.go
  46. 6
      pkg/services/alerting/notifiers/teams_test.go
  47. 8
      pkg/services/alerting/notifiers/telegram.go
  48. 12
      pkg/services/alerting/notifiers/telegram_test.go
  49. 8
      pkg/services/alerting/notifiers/threema.go
  50. 10
      pkg/services/alerting/notifiers/threema_test.go
  51. 8
      pkg/services/alerting/notifiers/victorops.go
  52. 12
      pkg/services/alerting/notifiers/victorops_test.go
  53. 8
      pkg/services/alerting/notifiers/webhook.go
  54. 4
      pkg/services/alerting/notifiers/webhook_test.go
  55. 11
      pkg/services/alerting/reader.go
  56. 10
      pkg/services/alerting/result_handler.go
  57. 19
      pkg/services/alerting/service.go
  58. 9
      pkg/services/alerting/service_test.go
  59. 4
      pkg/services/alerting/test_notification.go
  60. 2
      pkg/services/alerting/test_rule.go
  61. 12
      pkg/services/provisioning/notifiers/alert_notifications.go
  62. 8
      pkg/services/provisioning/notifiers/config_reader.go
  63. 14
      pkg/services/provisioning/notifiers/config_reader_test.go
  64. 11
      pkg/services/provisioning/provisioning.go
  65. 16
      pkg/services/sqlstore/alert_notification.go
  66. 276
      pkg/services/sqlstore/mockstore/mockstore.go

@ -202,6 +202,7 @@ var wireBasicSet = wire.NewSet(
var wireSet = wire.NewSet(
wireBasicSet,
sqlstore.ProvideService,
wire.Bind(new(alerting.AlertStore), new(*sqlstore.SQLStore)),
ngmetrics.ProvideService,
wire.Bind(new(notifications.Service), new(*notifications.NotificationService)),
wire.Bind(new(notifications.WebhookSender), new(*notifications.NotificationService)),
@ -214,6 +215,7 @@ var wireTestSet = wire.NewSet(
ProvideTestEnv,
sqlstore.ProvideServiceForTests,
ngmetrics.ProvideServiceForTest,
wire.Bind(new(alerting.AlertStore), new(*sqlstore.SQLStore)),
notifications.MockNotificationService,
wire.Bind(new(notifications.Service), new(*notifications.NotificationServiceMock)),

@ -28,7 +28,7 @@ type UsageStatsQuerier interface {
// configured in Grafana.
func (e *AlertEngine) QueryUsageStats(ctx context.Context) (*UsageStats, error) {
cmd := &models.GetAllAlertsQuery{}
err := e.Bus.Dispatch(ctx, cmd)
err := e.sqlStore.GetAllAlertQueryHandler(ctx, cmd)
if err != nil {
return nil, err
}
@ -63,7 +63,7 @@ func (e *AlertEngine) mapRulesToUsageStats(ctx context.Context, rules []*models.
result := map[string]int{}
for k, v := range typeCount {
query := &models.GetDataSourceQuery{Id: k}
err := e.Bus.Dispatch(ctx, query)
err := e.sqlStore.GetDataSource(ctx, query)
if err != nil {
return map[string]int{}, nil
}

@ -7,18 +7,18 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/stretchr/testify/require"
)
func TestAlertingUsageStats(t *testing.T) {
store := &AlertStoreMock{}
ae := &AlertEngine{
Bus: bus.New(),
sqlStore: store,
}
ae.Bus.AddHandler(func(ctx context.Context, query *models.GetAllAlertsQuery) error {
store.getAllAlerts = func(ctx context.Context, query *models.GetAllAlertsQuery) error {
var createFake = func(file string) *simplejson.Json {
// Ignore gosec warning G304 since it's a test
// nolint:gosec
@ -37,9 +37,9 @@ func TestAlertingUsageStats(t *testing.T) {
{Id: 3, Settings: createFake("testdata/settings/empty.json")},
}
return nil
})
}
ae.Bus.AddHandler(func(ctx context.Context, query *models.GetDataSourceQuery) error {
store.getDataSource = func(ctx context.Context, query *models.GetDataSourceQuery) error {
ds := map[int64]*models.DataSource{
1: {Type: "influxdb"},
2: {Type: "graphite"},
@ -54,7 +54,7 @@ func TestAlertingUsageStats(t *testing.T) {
query.Result = r
return nil
})
}
result, err := ae.QueryUsageStats(context.Background())
require.NoError(t, err, "getAlertingUsage should not return error")

@ -13,7 +13,6 @@ import (
gocontext "context"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/null"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
@ -140,7 +139,7 @@ func (c *QueryCondition) executeQuery(context *alerting.EvalContext, timeRange l
OrgId: context.Rule.OrgID,
}
if err := bus.Dispatch(context.Ctx, getDsInfo); err != nil {
if err := context.Store.GetDataSource(context.Ctx, getDsInfo); err != nil {
return nil, fmt.Errorf("could not find datasource: %w", err)
}

@ -4,10 +4,10 @@ import (
"context"
"testing"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
"github.com/grafana/grafana/pkg/tsdb/legacydata"
@ -137,16 +137,15 @@ func (rh fakeIntervalTestReqHandler) HandleRequest(ctx context.Context, dsInfo *
//nolint: staticcheck // legacydata.DataResponse deprecated
func applyScenario(t *testing.T, timeRange string, dataSourceJsonData *simplejson.Json, queryModel string, verifier func(query legacydata.DataSubQuery)) {
t.Run("desc", func(t *testing.T) {
bus.AddHandler("test", func(ctx context.Context, query *models.GetDataSourceQuery) error {
query.Result = &models.DataSource{Id: 1, Type: "graphite", JsonData: dataSourceJsonData}
return nil
})
store := mockstore.NewSQLStoreMock()
store.ExpectedDatasource = &models.DataSource{Id: 1, Type: "graphite", JsonData: dataSourceJsonData}
ctx := &queryIntervalTestContext{}
ctx.result = &alerting.EvalContext{
Ctx: context.Background(),
Rule: &alerting.Rule{},
RequestValidator: &validations.OSSPluginRequestValidator{},
Store: store,
}
jsonModel, err := simplejson.NewJson([]byte(`{

@ -6,13 +6,13 @@ import (
"testing"
"time"
"github.com/grafana/grafana/pkg/services/sqlstore/mockstore"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/grafana/grafana/pkg/tsdb/legacydata"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/null"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
@ -35,10 +35,8 @@ func newTimeSeriesPointsFromArgs(values ...float64) legacydata.DataTimeSeriesPoi
func TestQueryCondition(t *testing.T) {
setup := func() *queryConditionTestContext {
ctx := &queryConditionTestContext{}
bus.AddHandler("test", func(ctx context.Context, query *models.GetDataSourceQuery) error {
query.Result = &models.DataSource{Id: 1, Type: "graphite"}
return nil
})
store := mockstore.NewSQLStoreMock()
store.ExpectedDatasource = &models.DataSource{Id: 1, Type: "graphite"}
ctx.reducer = `{"type":"avg"}`
ctx.evaluator = `{"type":"gt","params":[100]}`
@ -46,6 +44,7 @@ func TestQueryCondition(t *testing.T) {
Ctx: context.Background(),
Rule: &alerting.Rule{},
RequestValidator: &validations.OSSPluginRequestValidator{},
Store: store,
}
return ctx
}

@ -16,11 +16,25 @@ import (
"github.com/grafana/grafana/pkg/infra/usagestats"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/services/rendering"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/legacydata"
)
// AlertStore is a subset of SQLStore API to satisfy the needs of the alerting service.
// A subset is needed to make it easier to mock during the tests.
type AlertStore interface {
GetAllAlertQueryHandler(context.Context, *models.GetAllAlertsQuery) error
GetDataSource(context.Context, *models.GetDataSourceQuery) error
GetDashboardUIDById(context.Context, *models.GetDashboardRefByIdQuery) error
SetAlertNotificationStateToCompleteCommand(context.Context, *models.SetAlertNotificationStateToCompleteCommand) error
SetAlertNotificationStateToPendingCommand(context.Context, *models.SetAlertNotificationStateToPendingCommand) error
GetAlertNotificationsWithUidToSend(context.Context, *models.GetAlertNotificationsWithUidToSendQuery) error
GetOrCreateAlertNotificationState(context.Context, *models.GetOrCreateNotificationStateQuery) error
SetAlertState(context.Context, *models.SetAlertStateCommand) error
}
// AlertEngine is the background process that
// schedules alert evaluations and makes sure notifications
// are sent.
@ -40,6 +54,7 @@ type AlertEngine struct {
resultHandler resultHandler
usageStatsService usagestats.Service
tracer tracing.Tracer
sqlStore AlertStore
}
// IsDisabled returns true if the alerting service is disabled for this instance.
@ -50,7 +65,7 @@ func (e *AlertEngine) IsDisabled() bool {
// ProvideAlertEngine returns a new AlertEngine.
func ProvideAlertEngine(renderer rendering.Service, bus bus.Bus, requestValidator models.PluginRequestValidator,
dataService legacydata.RequestHandler, usageStatsService usagestats.Service, encryptionService encryption.Internal,
cfg *setting.Cfg, tracer tracing.Tracer) *AlertEngine {
notificationService *notifications.NotificationService, tracer tracing.Tracer, sqlStore AlertStore, cfg *setting.Cfg) *AlertEngine {
e := &AlertEngine{
Cfg: cfg,
RenderService: renderer,
@ -59,14 +74,15 @@ func ProvideAlertEngine(renderer rendering.Service, bus bus.Bus, requestValidato
DataService: dataService,
usageStatsService: usageStatsService,
tracer: tracer,
sqlStore: sqlStore,
}
e.ticker = NewTicker(time.Now(), time.Second*0, clock.New(), 1)
e.execQueue = make(chan *Job, 1000)
e.scheduler = newScheduler()
e.evalHandler = NewEvalHandler(e.DataService)
e.ruleReader = newRuleReader()
e.ruleReader = newRuleReader(sqlStore)
e.log = log.New("alerting.engine")
e.resultHandler = newResultHandler(e.RenderService, encryptionService.GetDecryptedValue)
e.resultHandler = newResultHandler(e.RenderService, sqlStore, notificationService, encryptionService.GetDecryptedValue)
e.registerUsageMetrics()
@ -179,7 +195,7 @@ func (e *AlertEngine) processJob(attemptID int, attemptChan chan int, cancelChan
alertCtx, cancelFn := context.WithTimeout(context.Background(), setting.AlertingEvaluationTimeout)
cancelChan <- cancelFn
alertCtx, span := e.tracer.Start(alertCtx, "alert execution")
evalContext := NewEvalContext(alertCtx, job.Rule, e.RequestValidator)
evalContext := NewEvalContext(alertCtx, job.Rule, e.RequestValidator, e.sqlStore)
evalContext.Ctx = alertCtx
go func() {

@ -24,7 +24,7 @@ func TestEngineTimeouts(t *testing.T) {
usMock := &usagestats.UsageStatsMock{T: t}
tracer, err := tracing.InitializeTracerForTest()
require.NoError(t, err)
engine := ProvideAlertEngine(nil, nil, nil, nil, usMock, ossencryption.ProvideService(), setting.NewCfg(), tracer)
engine := ProvideAlertEngine(nil, nil, nil, nil, usMock, ossencryption.ProvideService(), nil, tracer, nil, setting.NewCfg())
setting.AlertingNotificationTimeout = 30 * time.Second
setting.AlertingMaxAttempts = 3
engine.resultHandler = &FakeResultHandler{}

@ -43,12 +43,66 @@ func (handler *FakeResultHandler) handle(evalContext *EvalContext) error {
return nil
}
// A mock implementation of the AlertStore interface, allowing to override certain methods individually
type AlertStoreMock struct {
getAllAlerts func(context.Context, *models.GetAllAlertsQuery) error
getDataSource func(context.Context, *models.GetDataSourceQuery) error
getAlertNotificationsWithUidToSend func(ctx context.Context, query *models.GetAlertNotificationsWithUidToSendQuery) error
getOrCreateNotificationState func(ctx context.Context, query *models.GetOrCreateNotificationStateQuery) error
}
func (a *AlertStoreMock) GetDataSource(c context.Context, cmd *models.GetDataSourceQuery) error {
if a.getDataSource != nil {
return a.getDataSource(c, cmd)
}
return nil
}
func (a *AlertStoreMock) GetAllAlertQueryHandler(c context.Context, cmd *models.GetAllAlertsQuery) error {
if a.getAllAlerts != nil {
return a.getAllAlerts(c, cmd)
}
return nil
}
func (a *AlertStoreMock) GetAlertNotificationsWithUidToSend(c context.Context, cmd *models.GetAlertNotificationsWithUidToSendQuery) error {
if a.getAlertNotificationsWithUidToSend != nil {
return a.getAlertNotificationsWithUidToSend(c, cmd)
}
return nil
}
func (a *AlertStoreMock) GetOrCreateAlertNotificationState(c context.Context, cmd *models.GetOrCreateNotificationStateQuery) error {
if a.getOrCreateNotificationState != nil {
return a.getOrCreateNotificationState(c, cmd)
}
return nil
}
func (a *AlertStoreMock) GetDashboardUIDById(_ context.Context, _ *models.GetDashboardRefByIdQuery) error {
return nil
}
func (a *AlertStoreMock) SetAlertNotificationStateToCompleteCommand(_ context.Context, _ *models.SetAlertNotificationStateToCompleteCommand) error {
return nil
}
func (a *AlertStoreMock) SetAlertNotificationStateToPendingCommand(_ context.Context, _ *models.SetAlertNotificationStateToPendingCommand) error {
return nil
}
func (a *AlertStoreMock) SetAlertState(_ context.Context, _ *models.SetAlertStateCommand) error {
return nil
}
func TestEngineProcessJob(t *testing.T) {
bus := bus.New()
usMock := &usagestats.UsageStatsMock{T: t}
tracer, err := tracing.InitializeTracerForTest()
require.NoError(t, err)
engine := ProvideAlertEngine(nil, bus, nil, nil, usMock, ossencryption.ProvideService(), setting.NewCfg(), tracer)
store := &AlertStoreMock{}
engine := ProvideAlertEngine(nil, bus, nil, nil, usMock, ossencryption.ProvideService(), nil, tracer, store, setting.NewCfg())
setting.AlertingEvaluationTimeout = 30 * time.Second
setting.AlertingNotificationTimeout = 30 * time.Second
setting.AlertingMaxAttempts = 3
@ -56,19 +110,19 @@ func TestEngineProcessJob(t *testing.T) {
job := &Job{running: true, Rule: &Rule{}}
t.Run("Should register usage metrics func", func(t *testing.T) {
bus.AddHandler(func(ctx context.Context, q *models.GetAllAlertsQuery) error {
store.getAllAlerts = func(ctx context.Context, q *models.GetAllAlertsQuery) error {
settings, err := simplejson.NewJson([]byte(`{"conditions": [{"query": { "datasourceId": 1}}]}`))
if err != nil {
return err
}
q.Result = []*models.Alert{{Settings: settings}}
return nil
})
}
bus.AddHandler(func(ctx context.Context, q *models.GetDataSourceQuery) error {
store.getDataSource = func(ctx context.Context, q *models.GetDataSourceQuery) error {
q.Result = &models.DataSource{Id: 1, Type: models.DS_PROMETHEUS}
return nil
})
}
report, err := usMock.GetUsageReport(context.Background())
require.Nil(t, err)

@ -6,7 +6,6 @@ import (
"regexp"
"time"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
@ -36,10 +35,12 @@ type EvalContext struct {
RequestValidator models.PluginRequestValidator
Ctx context.Context
Store AlertStore
}
// NewEvalContext is the EvalContext constructor.
func NewEvalContext(alertCtx context.Context, rule *Rule, requestValidator models.PluginRequestValidator) *EvalContext {
func NewEvalContext(alertCtx context.Context, rule *Rule, requestValidator models.PluginRequestValidator, sqlStore AlertStore) *EvalContext {
return &EvalContext{
Ctx: alertCtx,
StartTime: time.Now(),
@ -49,6 +50,7 @@ func NewEvalContext(alertCtx context.Context, rule *Rule, requestValidator model
Log: log.New("alerting.evalContext"),
PrevAlertState: rule.State,
RequestValidator: requestValidator,
Store: sqlStore,
}
}
@ -108,7 +110,7 @@ func (c *EvalContext) GetDashboardUID() (*models.DashboardRef, error) {
}
uidQuery := &models.GetDashboardRefByIdQuery{Id: c.Rule.DashboardID}
if err := bus.Dispatch(c.Ctx, uidQuery); err != nil {
if err := c.Store.GetDashboardUIDById(c.Ctx, uidQuery); err != nil {
return nil, err
}

@ -15,7 +15,7 @@ import (
)
func TestStateIsUpdatedWhenNeeded(t *testing.T) {
ctx := NewEvalContext(context.Background(), &Rule{Conditions: []Condition{&conditionStub{firing: true}}}, &validations.OSSPluginRequestValidator{})
ctx := NewEvalContext(context.Background(), &Rule{Conditions: []Condition{&conditionStub{firing: true}}}, &validations.OSSPluginRequestValidator{}, nil)
t.Run("ok -> alerting", func(t *testing.T) {
ctx.PrevAlertState = models.AlertStateOK
@ -200,7 +200,7 @@ func TestGetStateFromEvalContext(t *testing.T) {
}
for _, tc := range tcs {
evalContext := NewEvalContext(context.Background(), &Rule{Conditions: []Condition{&conditionStub{firing: true}}}, &validations.OSSPluginRequestValidator{})
evalContext := NewEvalContext(context.Background(), &Rule{Conditions: []Condition{&conditionStub{firing: true}}}, &validations.OSSPluginRequestValidator{}, nil)
tc.applyFn(evalContext)
newState := evalContext.GetNewState()

@ -29,7 +29,7 @@ func TestAlertingEvaluationHandler(t *testing.T) {
Conditions: []Condition{&conditionStub{
firing: true,
}},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
handler.Eval(context)
require.Equal(t, true, context.Firing)
@ -39,7 +39,7 @@ func TestAlertingEvaluationHandler(t *testing.T) {
t.Run("Show return triggered with single passing condition2", func(t *testing.T) {
context := NewEvalContext(context.Background(), &Rule{
Conditions: []Condition{&conditionStub{firing: true, operator: "and"}},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
handler.Eval(context)
require.Equal(t, true, context.Firing)
@ -52,7 +52,7 @@ func TestAlertingEvaluationHandler(t *testing.T) {
&conditionStub{firing: true, operator: "and", matches: []*EvalMatch{{}, {}}},
&conditionStub{firing: false, operator: "and"},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
handler.Eval(context)
require.Equal(t, false, context.Firing)
@ -65,7 +65,7 @@ func TestAlertingEvaluationHandler(t *testing.T) {
&conditionStub{firing: true, operator: "and"},
&conditionStub{firing: false, operator: "or"},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
handler.Eval(context)
require.Equal(t, true, context.Firing)
@ -78,7 +78,7 @@ func TestAlertingEvaluationHandler(t *testing.T) {
&conditionStub{firing: true, operator: "and"},
&conditionStub{firing: false, operator: "and"},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
handler.Eval(context)
require.Equal(t, false, context.Firing)
@ -92,7 +92,7 @@ func TestAlertingEvaluationHandler(t *testing.T) {
&conditionStub{firing: true, operator: "and"},
&conditionStub{firing: false, operator: "or"},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
handler.Eval(context)
require.Equal(t, true, context.Firing)
@ -106,7 +106,7 @@ func TestAlertingEvaluationHandler(t *testing.T) {
&conditionStub{firing: false, operator: "and"},
&conditionStub{firing: false, operator: "or"},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
handler.Eval(context)
require.Equal(t, false, context.Firing)
@ -120,7 +120,7 @@ func TestAlertingEvaluationHandler(t *testing.T) {
&conditionStub{firing: false, operator: "and"},
&conditionStub{firing: true, operator: "and"},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
handler.Eval(context)
require.Equal(t, false, context.Firing)
@ -134,7 +134,7 @@ func TestAlertingEvaluationHandler(t *testing.T) {
&conditionStub{firing: false, operator: "or"},
&conditionStub{firing: true, operator: "or"},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
handler.Eval(context)
require.Equal(t, true, context.Firing)
@ -148,7 +148,7 @@ func TestAlertingEvaluationHandler(t *testing.T) {
&conditionStub{firing: false, operator: "or"},
&conditionStub{firing: false, operator: "or"},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
handler.Eval(context)
require.Equal(t, false, context.Firing)
@ -163,7 +163,7 @@ func TestAlertingEvaluationHandler(t *testing.T) {
&conditionStub{operator: "or", noData: false},
&conditionStub{operator: "or", noData: false},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
handler.Eval(context)
require.False(t, context.NoDataFound)
@ -174,7 +174,7 @@ func TestAlertingEvaluationHandler(t *testing.T) {
Conditions: []Condition{
&conditionStub{operator: "and", noData: true},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
handler.Eval(context)
require.Equal(t, false, context.Firing)
@ -187,7 +187,7 @@ func TestAlertingEvaluationHandler(t *testing.T) {
&conditionStub{operator: "and", noData: true},
&conditionStub{operator: "and", noData: false},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
handler.Eval(context)
require.True(t, context.NoDataFound)
@ -199,7 +199,7 @@ func TestAlertingEvaluationHandler(t *testing.T) {
&conditionStub{operator: "or", noData: true},
&conditionStub{operator: "or", noData: false},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
handler.Eval(context)
require.True(t, context.NoDataFound)

@ -6,11 +6,11 @@ import (
"fmt"
"time"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/imguploader"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/services/rendering"
"github.com/grafana/grafana/pkg/setting"
)
@ -83,18 +83,22 @@ type ShowWhen struct {
Is string `json:"is"`
}
func newNotificationService(renderService rendering.Service, decryptFn GetDecryptedValueFn) *notificationService {
func newNotificationService(renderService rendering.Service, sqlStore AlertStore, notificationSvc *notifications.NotificationService, decryptFn GetDecryptedValueFn) *notificationService {
return &notificationService{
log: log.New("alerting.notifier"),
renderService: renderService,
decryptFn: decryptFn,
log: log.New("alerting.notifier"),
renderService: renderService,
sqlStore: sqlStore,
notificationService: notificationSvc,
decryptFn: decryptFn,
}
}
type notificationService struct {
log log.Logger
renderService rendering.Service
decryptFn GetDecryptedValueFn
log log.Logger
renderService rendering.Service
sqlStore AlertStore
notificationService *notifications.NotificationService
decryptFn GetDecryptedValueFn
}
func (n *notificationService) SendIfNeeded(evalCtx *EvalContext) error {
@ -152,7 +156,7 @@ func (n *notificationService) sendAndMarkAsComplete(evalContext *EvalContext, no
Version: notifierState.state.Version,
}
return bus.Dispatch(evalContext.Ctx, cmd)
return n.sqlStore.SetAlertNotificationStateToCompleteCommand(evalContext.Ctx, cmd)
}
func (n *notificationService) sendNotification(evalContext *EvalContext, notifierState *notifierState) error {
@ -163,7 +167,7 @@ func (n *notificationService) sendNotification(evalContext *EvalContext, notifie
AlertRuleStateUpdatedVersion: evalContext.Rule.StateChanges,
}
err := bus.Dispatch(evalContext.Ctx, setPendingCmd)
err := n.sqlStore.SetAlertNotificationStateToPendingCommand(evalContext.Ctx, setPendingCmd)
if err != nil {
if errors.Is(err, models.ErrAlertNotificationStateVersionConflict) {
return nil
@ -251,13 +255,13 @@ func (n *notificationService) renderAndUploadImage(evalCtx *EvalContext, timeout
func (n *notificationService) getNeededNotifiers(orgID int64, notificationUids []string, evalContext *EvalContext) (notifierStateSlice, error) {
query := &models.GetAlertNotificationsWithUidToSendQuery{OrgId: orgID, Uids: notificationUids}
if err := bus.Dispatch(evalContext.Ctx, query); err != nil {
if err := n.sqlStore.GetAlertNotificationsWithUidToSend(evalContext.Ctx, query); err != nil {
return nil, err
}
var result notifierStateSlice
for _, notification := range query.Result {
not, err := InitNotifier(notification, n.decryptFn)
not, err := InitNotifier(notification, n.decryptFn, n.notificationService)
if err != nil {
n.log.Error("Could not create notifier", "notifier", notification.Uid, "error", err)
continue
@ -269,7 +273,7 @@ func (n *notificationService) getNeededNotifiers(orgID int64, notificationUids [
OrgId: evalContext.Rule.OrgID,
}
err = bus.Dispatch(evalContext.Ctx, query)
err = n.sqlStore.GetOrCreateAlertNotificationState(evalContext.Ctx, query)
if err != nil {
n.log.Error("Could not get notification state.", "notifier", notification.Id, "error", err)
continue
@ -287,13 +291,13 @@ func (n *notificationService) getNeededNotifiers(orgID int64, notificationUids [
}
// InitNotifier instantiate a new notifier based on the model.
func InitNotifier(model *models.AlertNotification, fn GetDecryptedValueFn) (Notifier, error) {
func InitNotifier(model *models.AlertNotification, fn GetDecryptedValueFn, notificationService *notifications.NotificationService) (Notifier, error) {
notifierPlugin, found := notifierFactories[model.Type]
if !found {
return nil, fmt.Errorf("unsupported notification type %q", model.Type)
}
return notifierPlugin.Factory(model, fn)
return notifierPlugin.Factory(model, fn, notificationService)
}
// GetDecryptedValueFn is a function that returns the decrypted value of
@ -301,7 +305,7 @@ func InitNotifier(model *models.AlertNotification, fn GetDecryptedValueFn) (Noti
type GetDecryptedValueFn func(ctx context.Context, sjd map[string][]byte, key string, fallback string, secret string) string
// NotifierFactory is a signature for creating notifiers.
type NotifierFactory func(*models.AlertNotification, GetDecryptedValueFn) (Notifier, error)
type NotifierFactory func(*models.AlertNotification, GetDecryptedValueFn, notifications.Service) (Notifier, error)
var notifierFactories = make(map[string]*NotifierPlugin)

@ -5,6 +5,7 @@ import (
"testing"
"time"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/grafana/grafana/pkg/components/simplejson"
@ -21,17 +22,18 @@ import (
func TestNotificationService(t *testing.T) {
testRule := &Rule{Name: "Test", Message: "Something is bad"}
evalCtx := NewEvalContext(context.Background(), testRule, &validations.OSSPluginRequestValidator{})
store := &AlertStoreMock{}
evalCtx := NewEvalContext(context.Background(), testRule, &validations.OSSPluginRequestValidator{}, store)
testRuleTemplated := &Rule{Name: "Test latency ${quantile}", Message: "Something is bad on instance ${instance}"}
evalCtxWithMatch := NewEvalContext(context.Background(), testRuleTemplated, &validations.OSSPluginRequestValidator{})
evalCtxWithMatch := NewEvalContext(context.Background(), testRuleTemplated, &validations.OSSPluginRequestValidator{}, store)
evalCtxWithMatch.EvalMatches = []*EvalMatch{{
Tags: map[string]string{
"instance": "localhost:3000",
"quantile": "0.99",
},
}}
evalCtxWithoutMatch := NewEvalContext(context.Background(), testRuleTemplated, &validations.OSSPluginRequestValidator{})
evalCtxWithoutMatch := NewEvalContext(context.Background(), testRuleTemplated, &validations.OSSPluginRequestValidator{}, store)
notificationServiceScenario(t, "Given alert rule with upload image enabled should render and upload image and send notification",
evalCtx, true, func(sc *scenarioContext) {
@ -177,7 +179,9 @@ func notificationServiceScenario(t *testing.T, name string, evalCtx *EvalContext
evalCtx.dashboardRef = &models.DashboardRef{Uid: "db-uid"}
bus.AddHandler("test", func(ctx context.Context, query *models.GetAlertNotificationsWithUidToSendQuery) error {
store := evalCtx.Store.(*AlertStoreMock)
store.getAlertNotificationsWithUidToSend = func(ctx context.Context, query *models.GetAlertNotificationsWithUidToSendQuery) error {
query.Result = []*models.AlertNotification{
{
Id: 1,
@ -188,9 +192,9 @@ func notificationServiceScenario(t *testing.T, name string, evalCtx *EvalContext
},
}
return nil
})
}
bus.AddHandler("test", func(ctx context.Context, query *models.GetOrCreateNotificationStateQuery) error {
store.getOrCreateNotificationState = func(ctx context.Context, query *models.GetOrCreateNotificationStateQuery) error {
query.Result = &models.AlertNotificationState{
AlertId: evalCtx.Rule.ID,
AlertRuleStateUpdatedVersion: 1,
@ -199,7 +203,7 @@ func notificationServiceScenario(t *testing.T, name string, evalCtx *EvalContext
State: models.AlertNotificationStateUnknown,
}
return nil
})
}
bus.AddHandler("test", func(ctx context.Context, cmd *models.SetAlertNotificationStateToPendingCommand) error {
return nil
@ -263,7 +267,7 @@ func notificationServiceScenario(t *testing.T, name string, evalCtx *EvalContext
},
}
scenarioCtx.notificationService = newNotificationService(renderService, nil)
scenarioCtx.notificationService = newNotificationService(renderService, store, nil, nil)
fn(scenarioCtx)
})
}
@ -279,7 +283,7 @@ type testNotifier struct {
Frequency time.Duration
}
func newTestNotifier(model *models.AlertNotification, _ GetDecryptedValueFn) (Notifier, error) {
func newTestNotifier(model *models.AlertNotification, _ GetDecryptedValueFn, ns notifications.Service) (Notifier, error) {
uploadImage := true
value, exist := model.Settings.CheckGet("uploadImage")
if exist {

@ -7,11 +7,11 @@ import (
"strings"
"time"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
@ -50,7 +50,7 @@ func init() {
}
// NewAlertmanagerNotifier returns a new Alertmanager notifier
func NewAlertmanagerNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewAlertmanagerNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
urlString := model.Settings.Get("url").MustString()
if urlString == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@ -67,7 +67,7 @@ func NewAlertmanagerNotifier(model *models.AlertNotification, fn alerting.GetDec
basicAuthPassword := fn(context.Background(), model.SecureSettings, "basicAuthPassword", model.Settings.Get("basicAuthPassword").MustString(), setting.SecretKey)
return &AlertmanagerNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
URL: url,
BasicAuthUser: basicAuthUser,
BasicAuthPassword: basicAuthPassword,
@ -183,7 +183,7 @@ func (am *AlertmanagerNotifier) Notify(evalContext *alerting.EvalContext) error
Body: string(body),
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := am.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
am.log.Error("Failed to send alertmanager", "error", err, "alertmanager", am.Name, "url", url)
errCnt++
}

@ -68,7 +68,7 @@ func TestWhenAlertManagerShouldNotify(t *testing.T) {
am := &AlertmanagerNotifier{log: log.New("test.logger")}
evalContext := alerting.NewEvalContext(context.Background(), &alerting.Rule{
State: tc.prevState,
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
evalContext.Rule.State = tc.newState
@ -92,7 +92,7 @@ func TestAlertmanagerNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewAlertmanagerNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := NewAlertmanagerNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -106,7 +106,7 @@ func TestAlertmanagerNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewAlertmanagerNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewAlertmanagerNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
alertmanagerNotifier := not.(*AlertmanagerNotifier)
require.NoError(t, err)
@ -125,7 +125,7 @@ func TestAlertmanagerNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewAlertmanagerNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewAlertmanagerNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
alertmanagerNotifier := not.(*AlertmanagerNotifier)
require.NoError(t, err)

@ -7,6 +7,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
)
const (
@ -24,11 +25,13 @@ type NotifierBase struct {
DisableResolveMessage bool
Frequency time.Duration
NotificationService notifications.Service
log log.Logger
}
// NewNotifierBase returns a new `NotifierBase`.
func NewNotifierBase(model *models.AlertNotification) NotifierBase {
func NewNotifierBase(model *models.AlertNotification, notificationService notifications.Service) NotifierBase {
uploadImage := true
if value, exists := model.Settings.CheckGet("uploadImage"); exists {
uploadImage = value.MustBool()
@ -43,6 +46,7 @@ func NewNotifierBase(model *models.AlertNotification) NotifierBase {
SendReminder: model.SendReminder,
DisableResolveMessage: model.DisableResolveMessage,
Frequency: model.Frequency,
NotificationService: notificationService,
log: log.New("alerting.notifier." + model.Name),
}
}

@ -170,7 +170,7 @@ func TestShouldSendAlertNotification(t *testing.T) {
for _, tc := range tcs {
evalContext := alerting.NewEvalContext(context.Background(), &alerting.Rule{
State: tc.prevState,
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
if tc.state == nil {
tc.state = &models.AlertNotificationState{}
@ -197,24 +197,24 @@ func TestBaseNotifier(t *testing.T) {
t.Run("can parse false value", func(t *testing.T) {
bJSON.Set("uploadImage", false)
base := NewNotifierBase(model)
base := NewNotifierBase(model, nil)
require.False(t, base.UploadImage)
})
t.Run("can parse true value", func(t *testing.T) {
bJSON.Set("uploadImage", true)
base := NewNotifierBase(model)
base := NewNotifierBase(model, nil)
require.True(t, base.UploadImage)
})
t.Run("default value should be true for backwards compatibility", func(t *testing.T) {
base := NewNotifierBase(model)
base := NewNotifierBase(model, nil)
require.True(t, base.UploadImage)
})
t.Run("default value should be false for backwards compatibility", func(t *testing.T) {
base := NewNotifierBase(model)
base := NewNotifierBase(model, nil)
require.False(t, base.DisableResolveMessage)
})
}

@ -5,10 +5,10 @@ import (
"fmt"
"net/url"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
)
const defaultDingdingMsgType = "link"
@ -47,7 +47,7 @@ func init() {
})
}
func newDingDingNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func newDingDingNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@ -56,7 +56,7 @@ func newDingDingNotifier(model *models.AlertNotification, _ alerting.GetDecrypte
msgType := model.Settings.Get("msgType").MustString(defaultDingdingMsgType)
return &DingDingNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
MsgType: msgType,
URL: url,
log: log.New("alerting.notifier.dingding"),
@ -91,7 +91,7 @@ func (dd *DingDingNotifier) Notify(evalContext *alerting.EvalContext) error {
Body: string(body),
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := dd.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
dd.log.Error("Failed to send DingDing", "error", err, "dingding", dd.Name)
return err
}

@ -24,7 +24,7 @@ func TestDingDingNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := newDingDingNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := newDingDingNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
t.Run("settings should trigger incident", func(t *testing.T) {
@ -37,7 +37,7 @@ func TestDingDingNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := newDingDingNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := newDingDingNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
notifier := not.(*DingDingNotifier)
require.Nil(t, err)
@ -50,7 +50,7 @@ func TestDingDingNotifier(t *testing.T) {
&alerting.Rule{
State: models.AlertStateAlerting,
Message: `{host="localhost"}`,
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
_, err = notifier.genBody(evalContext, "")
require.Nil(t, err)
})

@ -9,11 +9,11 @@ import (
"strconv"
"strings"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
@ -57,7 +57,7 @@ func init() {
})
}
func newDiscordNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func newDiscordNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
avatar := model.Settings.Get("avatar_url").MustString()
content := model.Settings.Get("content").MustString()
url := model.Settings.Get("url").MustString()
@ -67,7 +67,7 @@ func newDiscordNotifier(model *models.AlertNotification, _ alerting.GetDecrypted
useDiscordUsername := model.Settings.Get("use_discord_username").MustBool(false)
return &DiscordNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
Content: content,
AvatarURL: avatar,
WebhookURL: url,
@ -177,7 +177,7 @@ func (dn *DiscordNotifier) Notify(evalContext *alerting.EvalContext) error {
}
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := dn.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
dn.log.Error("Failed to send notification to Discord", "error", err)
return err
}

@ -22,7 +22,7 @@ func TestDiscordNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := newDiscordNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := newDiscordNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -41,7 +41,7 @@ func TestDiscordNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := newDiscordNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := newDiscordNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
discordNotifier := not.(*DiscordNotifier)
require.Nil(t, err)

@ -3,12 +3,12 @@ package notifiers
import (
"os"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
@ -48,7 +48,7 @@ type EmailNotifier struct {
// NewEmailNotifier is the constructor function
// for the EmailNotifier.
func NewEmailNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewEmailNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
addressesString := model.Settings.Get("addresses").MustString()
singleEmail := model.Settings.Get("singleEmail").MustBool(false)
@ -60,7 +60,7 @@ func NewEmailNotifier(model *models.AlertNotification, _ alerting.GetDecryptedVa
addresses := util.SplitEmails(addressesString)
return &EmailNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
Addresses: addresses,
SingleEmail: singleEmail,
log: log.New("alerting.notifier.email"),
@ -117,7 +117,7 @@ func (en *EmailNotifier) Notify(evalContext *alerting.EvalContext) error {
}
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := en.NotificationService.SendEmailCommandHandlerSync(evalContext.Ctx, cmd); err != nil {
en.log.Error("Failed to send alert notification email", "error", err)
return err
}

@ -22,7 +22,7 @@ func TestEmailNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewEmailNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := NewEmailNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -39,7 +39,7 @@ func TestEmailNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewEmailNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewEmailNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
emailNotifier := not.(*EmailNotifier)
require.Nil(t, err)
@ -63,7 +63,7 @@ func TestEmailNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewEmailNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewEmailNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
emailNotifier := not.(*EmailNotifier)
require.Nil(t, err)

@ -5,10 +5,10 @@ import (
"fmt"
"time"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
@ -32,14 +32,14 @@ func init() {
})
}
func newGoogleChatNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func newGoogleChatNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
}
return &GoogleChatNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
URL: url,
log: log.New("alerting.notifier.googlechat"),
}, nil
@ -220,7 +220,7 @@ func (gcn *GoogleChatNotifier) Notify(evalContext *alerting.EvalContext) error {
Body: string(body),
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := gcn.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
gcn.log.Error("Failed to send Google Hangouts Chat alert", "error", err, "webhook", gcn.Name)
return err
}

@ -22,7 +22,7 @@ func TestGoogleChatNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := newGoogleChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := newGoogleChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -39,7 +39,7 @@ func TestGoogleChatNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := newGoogleChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := newGoogleChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
webhookNotifier := not.(*GoogleChatNotifier)
require.Nil(t, err)

@ -7,10 +7,10 @@ import (
"fmt"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
)
func init() {
@ -53,7 +53,7 @@ const (
// NewHipChatNotifier is the constructor functions
// for the HipChatNotifier
func NewHipChatNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewHipChatNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if strings.HasSuffix(url, "/") {
url = url[:len(url)-1]
@ -66,7 +66,7 @@ func NewHipChatNotifier(model *models.AlertNotification, _ alerting.GetDecrypted
roomID := model.Settings.Get("roomid").MustString()
return &HipChatNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
URL: url,
APIKey: apikey,
RoomID: roomID,
@ -177,7 +177,7 @@ func (hc *HipChatNotifier) Notify(evalContext *alerting.EvalContext) error {
hc.log.Info("Request payload", "json", string(data))
cmd := &models.SendWebhookSync{Url: hipURL, Body: string(data)}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := hc.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
hc.log.Error("Failed to send hipchat notification", "error", err, "webhook", hc.Name)
return err
}

@ -23,7 +23,7 @@ func TestHipChatNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewHipChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := NewHipChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -39,7 +39,7 @@ func TestHipChatNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewHipChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewHipChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
hipchatNotifier := not.(*HipChatNotifier)
require.Nil(t, err)
@ -65,7 +65,7 @@ func TestHipChatNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewHipChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewHipChatNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
hipchatNotifier := not.(*HipChatNotifier)
require.Nil(t, err)

@ -5,11 +5,11 @@ import (
"fmt"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
)
func init() {
@ -41,7 +41,7 @@ func init() {
}
// NewKafkaNotifier is the constructor function for the Kafka notifier.
func NewKafkaNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewKafkaNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
endpoint := model.Settings.Get("kafkaRestProxy").MustString()
if endpoint == "" {
return nil, alerting.ValidationError{Reason: "Could not find kafka rest proxy endpoint property in settings"}
@ -52,7 +52,7 @@ func NewKafkaNotifier(model *models.AlertNotification, _ alerting.GetDecryptedVa
}
return &KafkaNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
Endpoint: endpoint,
Topic: topic,
log: log.New("alerting.notifier.kafka"),
@ -124,7 +124,7 @@ func (kn *KafkaNotifier) Notify(evalContext *alerting.EvalContext) error {
},
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := kn.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
kn.log.Error("Failed to send notification to Kafka", "error", err, "body", string(body))
return err
}

@ -22,7 +22,7 @@ func TestKafkaNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewKafkaNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := NewKafkaNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -40,7 +40,7 @@ func TestKafkaNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewKafkaNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewKafkaNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
kafkaNotifier := not.(*KafkaNotifier)
require.Nil(t, err)

@ -5,10 +5,10 @@ import (
"fmt"
"net/url"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
@ -37,14 +37,14 @@ const (
)
// NewLINENotifier is the constructor for the LINE notifier
func NewLINENotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewLINENotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
token := fn(context.Background(), model.SecureSettings, "token", model.Settings.Get("token").MustString(), setting.SecretKey)
if token == "" {
return nil, alerting.ValidationError{Reason: "Could not find token in settings"}
}
return &LineNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
Token: token,
log: log.New("alerting.notifier.line"),
}, nil
@ -92,7 +92,7 @@ func (ln *LineNotifier) createAlert(evalContext *alerting.EvalContext) error {
Body: form.Encode(),
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := ln.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
ln.log.Error("Failed to send notification to LINE", "error", err, "body", body)
return err
}

@ -21,7 +21,7 @@ func TestLineNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewLINENotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := NewLINENotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
t.Run("settings should trigger incident", func(t *testing.T) {
@ -36,7 +36,7 @@ func TestLineNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewLINENotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewLINENotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
lineNotifier := not.(*LineNotifier)
require.Nil(t, err)

@ -5,11 +5,11 @@ import (
"fmt"
"strconv"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
@ -84,7 +84,7 @@ const (
)
// NewOpsGenieNotifier is the constructor for OpsGenie.
func NewOpsGenieNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewOpsGenieNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
autoClose := model.Settings.Get("autoClose").MustBool(true)
overridePriority := model.Settings.Get("overridePriority").MustBool(true)
apiKey := fn(context.Background(), model.SecureSettings, "apiKey", model.Settings.Get("apiKey").MustString(), setting.SecretKey)
@ -104,7 +104,7 @@ func NewOpsGenieNotifier(model *models.AlertNotification, fn alerting.GetDecrypt
}
return &OpsGenieNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
APIKey: apiKey,
APIUrl: apiURL,
AutoClose: autoClose,
@ -205,7 +205,7 @@ func (on *OpsGenieNotifier) createAlert(evalContext *alerting.EvalContext) error
},
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := on.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
on.log.Error("Failed to send notification to OpsGenie", "error", err, "body", string(body))
}
@ -229,7 +229,7 @@ func (on *OpsGenieNotifier) closeAlert(evalContext *alerting.EvalContext) error
},
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := on.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
on.log.Error("Failed to send notification to OpsGenie", "error", err, "body", string(body))
return err
}

@ -6,11 +6,11 @@ import (
"strings"
"testing"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/services/validations"
"github.com/stretchr/testify/require"
@ -28,7 +28,7 @@ func TestOpsGenieNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -45,7 +45,7 @@ func TestOpsGenieNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
opsgenieNotifier := not.(*OpsGenieNotifier)
require.Nil(t, err)
@ -69,7 +69,7 @@ func TestOpsGenieNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
require.Equal(t, reflect.TypeOf(err), reflect.TypeOf(alerting.ValidationError{}))
require.True(t, strings.HasSuffix(err.Error(), "Invalid value for sendTagsAs: \"not_a_valid_value\""))
@ -92,7 +92,8 @@ func TestOpsGenieNotifier(t *testing.T) {
Settings: settingsJSON,
}
notifier, notifierErr := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue) // unhandled error
notificationService := notifications.MockNotificationService()
notifier, notifierErr := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue, notificationService) // unhandled error
opsgenieNotifier := notifier.(*OpsGenieNotifier)
@ -102,22 +103,20 @@ func TestOpsGenieNotifier(t *testing.T) {
Message: "someMessage",
State: models.AlertStateAlerting,
AlertRuleTags: tagPairs,
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
evalContext.IsTestRun = true
tags := make([]string, 0)
details := make(map[string]interface{})
bus.AddHandler("alerting", func(ctx context.Context, cmd *models.SendWebhookSync) error {
bodyJSON, err := simplejson.NewJson([]byte(cmd.Body))
if err == nil {
tags = bodyJSON.Get("tags").MustStringArray([]string{})
details = bodyJSON.Get("details").MustMap(map[string]interface{}{})
}
return err
})
alertErr := opsgenieNotifier.createAlert(evalContext)
bodyJSON, err := simplejson.NewJson([]byte(notificationService.Webhook.Body))
if err == nil {
tags = bodyJSON.Get("tags").MustStringArray([]string{})
details = bodyJSON.Get("details").MustMap(map[string]interface{}{})
}
require.Nil(t, notifierErr)
require.Nil(t, alertErr)
require.Equal(t, tags, []string{"keyOnly", "aKey:aValue"})
@ -142,7 +141,8 @@ func TestOpsGenieNotifier(t *testing.T) {
Settings: settingsJSON,
}
notifier, notifierErr := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue) // unhandled error
notificationService := notifications.MockNotificationService()
notifier, notifierErr := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue, notificationService) // unhandled error
opsgenieNotifier := notifier.(*OpsGenieNotifier)
@ -152,22 +152,20 @@ func TestOpsGenieNotifier(t *testing.T) {
Message: "someMessage",
State: models.AlertStateAlerting,
AlertRuleTags: tagPairs,
}, nil)
}, nil, nil)
evalContext.IsTestRun = true
tags := make([]string, 0)
details := make(map[string]interface{})
bus.AddHandler("alerting", func(ctx context.Context, cmd *models.SendWebhookSync) error {
bodyJSON, err := simplejson.NewJson([]byte(cmd.Body))
if err == nil {
tags = bodyJSON.Get("tags").MustStringArray([]string{})
details = bodyJSON.Get("details").MustMap(map[string]interface{}{})
}
return err
})
alertErr := opsgenieNotifier.createAlert(evalContext)
bodyJSON, err := simplejson.NewJson([]byte(notificationService.Webhook.Body))
if err == nil {
tags = bodyJSON.Get("tags").MustStringArray([]string{})
details = bodyJSON.Get("details").MustMap(map[string]interface{}{})
}
require.Nil(t, notifierErr)
require.Nil(t, alertErr)
require.Equal(t, tags, []string{})
@ -192,7 +190,8 @@ func TestOpsGenieNotifier(t *testing.T) {
Settings: settingsJSON,
}
notifier, notifierErr := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue) // unhandled error
notificationService := notifications.MockNotificationService()
notifier, notifierErr := NewOpsGenieNotifier(model, ossencryption.ProvideService().GetDecryptedValue, notificationService) // unhandled error
opsgenieNotifier := notifier.(*OpsGenieNotifier)
@ -202,22 +201,20 @@ func TestOpsGenieNotifier(t *testing.T) {
Message: "someMessage",
State: models.AlertStateAlerting,
AlertRuleTags: tagPairs,
}, nil)
}, nil, nil)
evalContext.IsTestRun = true
tags := make([]string, 0)
details := make(map[string]interface{})
bus.AddHandler("alerting", func(ctx context.Context, cmd *models.SendWebhookSync) error {
bodyJSON, err := simplejson.NewJson([]byte(cmd.Body))
if err == nil {
tags = bodyJSON.Get("tags").MustStringArray([]string{})
details = bodyJSON.Get("details").MustMap(map[string]interface{}{})
}
return err
})
alertErr := opsgenieNotifier.createAlert(evalContext)
bodyJSON, err := simplejson.NewJson([]byte(notificationService.Webhook.Body))
if err == nil {
tags = bodyJSON.Get("tags").MustStringArray([]string{})
details = bodyJSON.Get("details").MustMap(map[string]interface{}{})
}
require.Nil(t, notifierErr)
require.Nil(t, alertErr)
require.Equal(t, tags, []string{"keyOnly", "aKey:aValue"})

@ -7,11 +7,11 @@ import (
"strings"
"time"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
@ -76,7 +76,7 @@ var (
)
// NewPagerdutyNotifier is the constructor for the PagerDuty notifier
func NewPagerdutyNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewPagerdutyNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
severity := model.Settings.Get("severity").MustString("critical")
autoResolve := model.Settings.Get("autoResolve").MustBool(false)
key := fn(context.Background(), model.SecureSettings, "integrationKey", model.Settings.Get("integrationKey").MustString(), setting.SecretKey)
@ -86,7 +86,7 @@ func NewPagerdutyNotifier(model *models.AlertNotification, fn alerting.GetDecryp
}
return &PagerdutyNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
Key: key,
Severity: severity,
AutoResolve: autoResolve,
@ -240,7 +240,7 @@ func (pn *PagerdutyNotifier) Notify(evalContext *alerting.EvalContext) error {
},
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := pn.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
pn.log.Error("Failed to send notification to Pagerduty", "error", err, "body", string(body))
return err
}

@ -39,7 +39,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err = NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err = NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -55,7 +55,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
pagerdutyNotifier := not.(*PagerdutyNotifier)
require.Nil(t, err)
@ -78,7 +78,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
pagerdutyNotifier := not.(*PagerdutyNotifier)
require.Nil(t, err)
@ -105,7 +105,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
pagerdutyNotifier := not.(*PagerdutyNotifier)
require.Nil(t, err)
@ -130,7 +130,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Nil(t, err)
pagerdutyNotifier := not.(*PagerdutyNotifier)
@ -139,7 +139,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Name: "someRule",
Message: "someMessage",
State: models.AlertStateAlerting,
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
evalContext.IsTestRun = true
payloadJSON, err := pagerdutyNotifier.buildEventPayload(evalContext)
@ -187,7 +187,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Nil(t, err)
pagerdutyNotifier := not.(*PagerdutyNotifier)
@ -195,7 +195,7 @@ func TestPagerdutyNotifier(t *testing.T) {
ID: 0,
Name: "someRule",
State: models.AlertStateAlerting,
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
evalContext.IsTestRun = true
payloadJSON, err := pagerdutyNotifier.buildEventPayload(evalContext)
@ -244,7 +244,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Nil(t, err)
pagerdutyNotifier := not.(*PagerdutyNotifier)
@ -253,7 +253,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Name: "someRule",
Message: "someMessage",
State: models.AlertStateAlerting,
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
evalContext.IsTestRun = true
evalContext.EvalMatches = []*alerting.EvalMatch{
{
@ -314,7 +314,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.NoError(t, err)
pagerdutyNotifier := not.(*PagerdutyNotifier)
@ -332,7 +332,7 @@ func TestPagerdutyNotifier(t *testing.T) {
{Key: "severity", Value: "warning"},
{Key: "dedup_key", Value: "key-" + strings.Repeat("x", 260)},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
evalContext.ImagePublicURL = "http://somewhere.com/omg_dont_panic.png"
evalContext.IsTestRun = true
@ -394,7 +394,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.NoError(t, err)
pagerdutyNotifier := not.(*PagerdutyNotifier)
@ -411,7 +411,7 @@ func TestPagerdutyNotifier(t *testing.T) {
{Key: "component", Value: "aComponent"},
{Key: "severity", Value: "info"},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
evalContext.ImagePublicURL = "http://somewhere.com/omg_dont_panic.png"
evalContext.IsTestRun = true
@ -473,7 +473,7 @@ func TestPagerdutyNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewPagerdutyNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.NoError(t, err)
pagerdutyNotifier := not.(*PagerdutyNotifier)
@ -490,7 +490,7 @@ func TestPagerdutyNotifier(t *testing.T) {
{Key: "component", Value: "aComponent"},
{Key: "severity", Value: "llama"},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
evalContext.ImagePublicURL = "http://somewhere.com/omg_dont_panic.png"
evalContext.IsTestRun = true

@ -11,10 +11,10 @@ import (
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
)
const pushoverEndpoint = "https://api.pushover.net/1/messages.json"
@ -194,7 +194,7 @@ func init() {
}
// NewPushoverNotifier is the constructor for the Pushover Notifier
func NewPushoverNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewPushoverNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
userKey := fn(context.Background(), model.SecureSettings, "userKey", model.Settings.Get("userKey").MustString(), setting.SecretKey)
APIToken := fn(context.Background(), model.SecureSettings, "apiToken", model.Settings.Get("apiToken").MustString(), setting.SecretKey)
device := model.Settings.Get("device").MustString()
@ -219,7 +219,7 @@ func NewPushoverNotifier(model *models.AlertNotification, fn alerting.GetDecrypt
return nil, alerting.ValidationError{Reason: "API token not given"}
}
return &PushoverNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
UserKey: userKey,
APIToken: APIToken,
AlertingPriority: alertingPriority,
@ -287,7 +287,7 @@ func (pn *PushoverNotifier) Notify(evalContext *alerting.EvalContext) error {
Body: uploadBody.String(),
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := pn.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
pn.log.Error("Failed to send pushover notification", "error", err, "webhook", pn.Name)
return err
}

@ -26,7 +26,7 @@ func TestPushoverNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewPushoverNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := NewPushoverNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -48,7 +48,7 @@ func TestPushoverNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewPushoverNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewPushoverNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
pushoverNotifier := not.(*PushoverNotifier)
require.Nil(t, err)
@ -74,7 +74,7 @@ func TestGenPushoverBody(t *testing.T) {
evalContext := alerting.NewEvalContext(context.Background(),
&alerting.Rule{
State: models.AlertStateAlerting,
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
_, pushoverBody, err := notifier.genPushoverBody(evalContext, "", "")
require.Nil(t, err)
@ -85,7 +85,7 @@ func TestGenPushoverBody(t *testing.T) {
evalContext := alerting.NewEvalContext(context.Background(),
&alerting.Rule{
State: models.AlertStateOK,
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
_, pushoverBody, err := notifier.genPushoverBody(evalContext, "", "")
require.Nil(t, err)

@ -5,11 +5,11 @@ import (
"strconv"
"strings"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
@ -61,14 +61,14 @@ func init() {
}
// NewSensuNotifier is the constructor for the Sensu Notifier.
func NewSensuNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewSensuNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
}
return &SensuNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
URL: url,
User: model.Settings.Get("username").MustString(),
Source: model.Settings.Get("source").MustString(),
@ -146,7 +146,7 @@ func (sn *SensuNotifier) Notify(evalContext *alerting.EvalContext) error {
HttpMethod: "POST",
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := sn.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
sn.log.Error("Failed to send sensu event", "error", err, "sensu", sn.Name)
return err
}

@ -22,7 +22,7 @@ func TestSensuNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewSensuNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := NewSensuNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -41,7 +41,7 @@ func TestSensuNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewSensuNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewSensuNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
sensuNotifier := not.(*SensuNotifier)
require.Nil(t, err)

@ -7,11 +7,11 @@ import (
"strings"
"time"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
@ -72,7 +72,7 @@ func init() {
}
// NewSensuGoNotifier is the constructor for the Sensu Go Notifier.
func NewSensuGoNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewSensuGoNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
apikey := fn(context.Background(), model.SecureSettings, "apikey", model.Settings.Get("apikey").MustString(), setting.SecretKey)
@ -84,7 +84,7 @@ func NewSensuGoNotifier(model *models.AlertNotification, fn alerting.GetDecrypte
}
return &SensuGoNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
URL: url,
Entity: model.Settings.Get("entity").MustString(),
Check: model.Settings.Get("check").MustString(),
@ -197,7 +197,7 @@ func (sn *SensuGoNotifier) Notify(evalContext *alerting.EvalContext) error {
"Authorization": fmt.Sprintf("Key %s", sn.APIKey),
},
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := sn.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
sn.log.Error("Failed to send Sensu Go event", "error", err, "sensugo", sn.Name)
return err
}

@ -21,7 +21,7 @@ func TestSensuGoNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err = NewSensuGoNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err = NewSensuGoNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
json = `
@ -42,7 +42,7 @@ func TestSensuGoNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewSensuGoNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewSensuGoNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.NoError(t, err)
sensuGoNotifier := not.(*SensuGoNotifier)

@ -16,10 +16,10 @@ import (
"strings"
"time"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
@ -121,7 +121,7 @@ func init() {
const slackAPIEndpoint = "https://slack.com/api/chat.postMessage"
// NewSlackNotifier is the constructor for the Slack notifier.
func NewSlackNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewSlackNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
urlStr := fn(context.Background(), model.SecureSettings, "url", model.Settings.Get("url").MustString(), setting.SecretKey)
if urlStr == "" {
urlStr = slackAPIEndpoint
@ -174,7 +174,7 @@ func NewSlackNotifier(model *models.AlertNotification, fn alerting.GetDecryptedV
return &SlackNotifier{
url: apiURL,
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
recipient: recipient,
username: username,
iconEmoji: iconEmoji,
@ -418,7 +418,7 @@ func (sn *SlackNotifier) slackFileUpload(evalContext *alerting.EvalContext, log
cmd := &models.SendWebhookSync{
Url: "https://slack.com/api/files.upload", Body: uploadBody.String(), HttpHeader: headers, HttpMethod: "POST",
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := sn.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
log.Error("Failed to upload slack image", "error", err, "webhook", "file.upload")
return err
}

@ -27,7 +27,7 @@ func TestSlackNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err = NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err = NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
assert.EqualError(t, err, "alert validation error: recipient must be specified when using the Slack chat API")
})
@ -45,7 +45,7 @@ func TestSlackNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.NoError(t, err)
slackNotifier := not.(*SlackNotifier)
assert.Equal(t, "ops", slackNotifier.Name)
@ -83,7 +83,7 @@ func TestSlackNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.NoError(t, err)
slackNotifier := not.(*SlackNotifier)
assert.Equal(t, "ops", slackNotifier.Name)
@ -131,7 +131,7 @@ func TestSlackNotifier(t *testing.T) {
SecureSettings: securedSettingsJSON,
}
not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.NoError(t, err)
slackNotifier := not.(*SlackNotifier)
assert.Equal(t, "ops", slackNotifier.Name)
@ -162,7 +162,7 @@ func TestSlackNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.NoError(t, err)
slackNotifier := not.(*SlackNotifier)
assert.Equal(t, "1ABCDE", slackNotifier.recipient)
@ -253,7 +253,7 @@ func TestSendSlackRequest(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewSlackNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.NoError(t, err)
slackNotifier := not.(*SlackNotifier)

@ -3,10 +3,10 @@ package notifiers
import (
"encoding/json"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
)
func init() {
@ -30,14 +30,14 @@ func init() {
}
// NewTeamsNotifier is the constructor for Teams notifier.
func NewTeamsNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewTeamsNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
}
return &TeamsNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
URL: url,
log: log.New("alerting.notifier.teams"),
}, nil
@ -135,7 +135,7 @@ func (tn *TeamsNotifier) Notify(evalContext *alerting.EvalContext) error {
data, _ := json.Marshal(&body)
cmd := &models.SendWebhookSync{Url: tn.URL, Body: string(data)}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := tn.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
tn.log.Error("Failed to send teams notification", "error", err, "webhook", tn.Name)
return err
}

@ -22,7 +22,7 @@ func TestTeamsNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewTeamsNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := NewTeamsNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -39,7 +39,7 @@ func TestTeamsNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewTeamsNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewTeamsNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
teamsNotifier := not.(*TeamsNotifier)
require.Nil(t, err)
@ -61,7 +61,7 @@ func TestTeamsNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewTeamsNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewTeamsNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
teamsNotifier := not.(*TeamsNotifier)
require.Nil(t, err)

@ -8,10 +8,10 @@ import (
"mime/multipart"
"os"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
@ -63,7 +63,7 @@ type TelegramNotifier struct {
}
// NewTelegramNotifier is the constructor for the Telegram notifier
func NewTelegramNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewTelegramNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
if model.Settings == nil {
return nil, alerting.ValidationError{Reason: "No Settings Supplied"}
}
@ -81,7 +81,7 @@ func NewTelegramNotifier(model *models.AlertNotification, fn alerting.GetDecrypt
}
return &TelegramNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
BotToken: botToken,
ChatID: chatID,
UploadImage: uploadImage,
@ -271,7 +271,7 @@ func (tn *TelegramNotifier) Notify(evalContext *alerting.EvalContext) error {
return err
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := tn.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
tn.log.Error("Failed to send webhook", "error", err, "webhook", tn.Name)
return err
}

@ -25,7 +25,7 @@ func TestTelegramNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewTelegramNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := NewTelegramNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -43,7 +43,7 @@ func TestTelegramNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewTelegramNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewTelegramNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
telegramNotifier := not.(*TelegramNotifier)
require.Nil(t, err)
@ -59,7 +59,7 @@ func TestTelegramNotifier(t *testing.T) {
Name: "This is an alarm",
Message: "Some kind of message.",
State: models.AlertStateOK,
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
caption := generateImageCaption(evalContext, "http://grafa.url/abcdef", "")
require.LessOrEqual(t, len(caption), 1024)
@ -75,7 +75,7 @@ func TestTelegramNotifier(t *testing.T) {
Name: "This is an alarm",
Message: "Some kind of message.",
State: models.AlertStateOK,
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
caption := generateImageCaption(evalContext,
"http://grafa.url/abcdefaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
@ -93,7 +93,7 @@ func TestTelegramNotifier(t *testing.T) {
Name: "This is an alarm",
Message: "Some kind of message that is too long for appending to our pretty little message, this line is actually exactly 197 chars long and I will get there in the end I promise I will. Yes siree that's it. But suddenly Telegram increased the length so now we need some lorem ipsum to fix this test. Here we go: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus consectetur molestie cursus. Donec suscipit egestas nisi. Proin ut efficitur ex. Mauris mi augue, volutpat a nisi vel, euismod dictum arcu. Sed quis tempor eros, sed malesuada dolor. Ut orci augue, viverra sit amet blandit quis, faucibus sit amet ex. Duis condimentum efficitur lectus, id dignissim quam tempor id. Morbi sollicitudin rhoncus diam, id tincidunt lectus scelerisque vitae. Etiam imperdiet semper sem, vel eleifend ligula mollis eget. Etiam ultrices fringilla lacus, sit amet pharetra ex blandit quis. Suspendisse in egestas neque, et posuere lectus. Vestibulum eu ex dui. Sed molestie nulla a lobortis scelerisque. Nulla ipsum ex, iaculis vitae vehicula sit amet, fermentum eu eros.",
State: models.AlertStateOK,
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
caption := generateImageCaption(evalContext,
"http://grafa.url/foo",
@ -110,7 +110,7 @@ func TestTelegramNotifier(t *testing.T) {
Name: "This is an alarm",
Message: "Some kind of message that is too long for appending to our pretty little message, this line is actually exactly 197 chars long and I will get there in the end I promise I will. Yes siree that's it. But suddenly Telegram increased the length so now we need some lorem ipsum to fix this test. Here we go: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus consectetur molestie cursus. Donec suscipit egestas nisi. Proin ut efficitur ex. Mauris mi augue, volutpat a nisi vel, euismod dictum arcu. Sed quis tempor eros, sed malesuada dolor. Ut orci augue, viverra sit amet blandit quis, faucibus sit amet ex. Duis condimentum efficitur lectus, id dignissim quam tempor id. Morbi sollicitudin rhoncus diam, id tincidunt lectus scelerisque vitae. Etiam imperdiet semper sem, vel eleifend ligula mollis eget. Etiam ultrices fringilla lacus, sit amet pharetra ex blandit quis. Suspendisse in egestas neque, et posuere lectus. Vestibulum eu ex dui. Sed molestie nulla a lobortis sceleri",
State: models.AlertStateOK,
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
caption := generateImageCaption(evalContext,
"http://grafa.url/foo",

@ -6,10 +6,10 @@ import (
"net/url"
"strings"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
@ -71,7 +71,7 @@ type ThreemaNotifier struct {
}
// NewThreemaNotifier is the constructor for the Threema notifier
func NewThreemaNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewThreemaNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
if model.Settings == nil {
return nil, alerting.ValidationError{Reason: "No Settings Supplied"}
}
@ -101,7 +101,7 @@ func NewThreemaNotifier(model *models.AlertNotification, fn alerting.GetDecrypte
}
return &ThreemaNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
GatewayID: gatewayID,
RecipientID: recipientID,
APISecret: apiSecret,
@ -158,7 +158,7 @@ func (notifier *ThreemaNotifier) Notify(evalContext *alerting.EvalContext) error
HttpMethod: "POST",
HttpHeader: headers,
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := notifier.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
notifier.log.Error("Failed to send webhook", "error", err, "webhook", notifier.Name)
return err
}

@ -24,7 +24,7 @@ func TestThreemaNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -43,7 +43,7 @@ func TestThreemaNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Nil(t, err)
threemaNotifier := not.(*ThreemaNotifier)
@ -70,7 +70,7 @@ func TestThreemaNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Nil(t, not)
var valErr alerting.ValidationError
require.True(t, errors.As(err, &valErr))
@ -92,7 +92,7 @@ func TestThreemaNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Nil(t, not)
var valErr alerting.ValidationError
require.True(t, errors.As(err, &valErr))
@ -114,7 +114,7 @@ func TestThreemaNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewThreemaNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Nil(t, not)
var valErr alerting.ValidationError
require.True(t, errors.As(err, &valErr))

@ -4,11 +4,11 @@ import (
"strings"
"time"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
@ -47,7 +47,7 @@ func init() {
// NewVictoropsNotifier creates an instance of VictoropsNotifier that
// handles posting notifications to Victorops REST API
func NewVictoropsNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewVictoropsNotifier(model *models.AlertNotification, _ alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
autoResolve := model.Settings.Get("autoResolve").MustBool(true)
url := model.Settings.Get("url").MustString()
if url == "" {
@ -56,7 +56,7 @@ func NewVictoropsNotifier(model *models.AlertNotification, _ alerting.GetDecrypt
noDataAlertType := model.Settings.Get("noDataAlertType").MustString(AlertStateWarning)
return &VictoropsNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
URL: url,
NoDataAlertType: noDataAlertType,
AutoResolve: autoResolve,
@ -156,7 +156,7 @@ func (vn *VictoropsNotifier) Notify(evalContext *alerting.EvalContext) error {
data, _ := bodyJSON.MarshalJSON()
cmd := &models.SendWebhookSync{Url: vn.URL, Body: string(data)}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := vn.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
vn.log.Error("Failed to send Victorops notification", "error", err, "webhook", vn.Name)
return err
}

@ -35,7 +35,7 @@ func TestVictoropsNotifier(t *testing.T) {
Settings: settingsJSON,
}
_, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -52,7 +52,7 @@ func TestVictoropsNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
victoropsNotifier := not.(*VictoropsNotifier)
require.Nil(t, err)
@ -76,7 +76,7 @@ func TestVictoropsNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Nil(t, err)
victoropsNotifier := not.(*VictoropsNotifier)
@ -90,7 +90,7 @@ func TestVictoropsNotifier(t *testing.T) {
{Key: "keyOnly"},
{Key: "severity", Value: "warning"},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
evalContext.IsTestRun = true
payload, err := victoropsNotifier.buildEventPayload(evalContext)
@ -124,7 +124,7 @@ func TestVictoropsNotifier(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewVictoropsNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Nil(t, err)
victoropsNotifier := not.(*VictoropsNotifier)
@ -138,7 +138,7 @@ func TestVictoropsNotifier(t *testing.T) {
{Key: "keyOnly"},
{Key: "severity", Value: "warning"},
},
}, &validations.OSSPluginRequestValidator{})
}, &validations.OSSPluginRequestValidator{}, nil)
evalContext.IsTestRun = true
payload, err := victoropsNotifier.buildEventPayload(evalContext)

@ -4,10 +4,10 @@ import (
"context"
"encoding/json"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/setting"
)
@ -60,7 +60,7 @@ func init() {
// NewWebHookNotifier is the constructor for
// the WebHook notifier.
func NewWebHookNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn) (alerting.Notifier, error) {
func NewWebHookNotifier(model *models.AlertNotification, fn alerting.GetDecryptedValueFn, ns notifications.Service) (alerting.Notifier, error) {
url := model.Settings.Get("url").MustString()
if url == "" {
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
@ -69,7 +69,7 @@ func NewWebHookNotifier(model *models.AlertNotification, fn alerting.GetDecrypte
password := fn(context.Background(), model.SecureSettings, "password", model.Settings.Get("password").MustString(), setting.SecretKey)
return &WebhookNotifier{
NotifierBase: NewNotifierBase(model),
NotifierBase: NewNotifierBase(model, ns),
URL: url,
User: model.Settings.Get("username").MustString(),
Password: password,
@ -153,7 +153,7 @@ func (wn *WebhookNotifier) Notify(evalContext *alerting.EvalContext) error {
HttpMethod: wn.HTTPMethod,
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := wn.NotificationService.SendWebhookSync(evalContext.Ctx, cmd); err != nil {
wn.log.Error("Failed to send webhook", "error", err, "webhook", wn.Name)
return err
}

@ -22,7 +22,7 @@ func TestWebhookNotifier_parsingFromSettings(t *testing.T) {
Settings: settingsJSON,
}
_, err = NewWebHookNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
_, err = NewWebHookNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.Error(t, err)
})
@ -37,7 +37,7 @@ func TestWebhookNotifier_parsingFromSettings(t *testing.T) {
Settings: settingsJSON,
}
not, err := NewWebHookNotifier(model, ossencryption.ProvideService().GetDecryptedValue)
not, err := NewWebHookNotifier(model, ossencryption.ProvideService().GetDecryptedValue, nil)
require.NoError(t, err)
webhookNotifier := not.(*WebhookNotifier)

@ -4,7 +4,6 @@ import (
"context"
"sync"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/models"
@ -16,12 +15,14 @@ type ruleReader interface {
type defaultRuleReader struct {
sync.RWMutex
log log.Logger
sqlStore AlertStore
log log.Logger
}
func newRuleReader() *defaultRuleReader {
func newRuleReader(sqlStore AlertStore) *defaultRuleReader {
ruleReader := &defaultRuleReader{
log: log.New("alerting.ruleReader"),
sqlStore: sqlStore,
log: log.New("alerting.ruleReader"),
}
return ruleReader
@ -30,7 +31,7 @@ func newRuleReader() *defaultRuleReader {
func (arr *defaultRuleReader) fetch(ctx context.Context) []*Rule {
cmd := &models.GetAllAlertsQuery{}
if err := bus.Dispatch(ctx, cmd); err != nil {
if err := arr.sqlStore.GetAllAlertQueryHandler(ctx, cmd); err != nil {
arr.log.Error("Could not load alerts", "error", err)
return []*Rule{}
}

@ -5,13 +5,13 @@ import (
"errors"
"time"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/annotations"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/services/rendering"
)
@ -21,13 +21,15 @@ type resultHandler interface {
type defaultResultHandler struct {
notifier *notificationService
sqlStore AlertStore
log log.Logger
}
func newResultHandler(renderService rendering.Service, decryptFn GetDecryptedValueFn) *defaultResultHandler {
func newResultHandler(renderService rendering.Service, sqlStore AlertStore, notificationService *notifications.NotificationService, decryptFn GetDecryptedValueFn) *defaultResultHandler {
return &defaultResultHandler{
log: log.New("alerting.resultHandler"),
notifier: newNotificationService(renderService, decryptFn),
sqlStore: sqlStore,
notifier: newNotificationService(renderService, sqlStore, notificationService, decryptFn),
}
}
@ -58,7 +60,7 @@ func (handler *defaultResultHandler) handle(evalContext *EvalContext) error {
EvalData: annotationData,
}
if err := bus.Dispatch(evalContext.Ctx, cmd); err != nil {
if err := handler.sqlStore.SetAlertState(evalContext.Ctx, cmd); err != nil {
if errors.Is(err, models.ErrCannotChangeStateOnPausedAlert) {
handler.log.Error("Cannot change state on alert that's paused", "error", err)
return err

@ -6,22 +6,25 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting"
)
type AlertNotificationService struct {
Bus bus.Bus
SQLStore *sqlstore.SQLStore
EncryptionService encryption.Internal
Bus bus.Bus
SQLStore *sqlstore.SQLStore
EncryptionService encryption.Internal
NotificationService *notifications.NotificationService
}
func ProvideService(bus bus.Bus, store *sqlstore.SQLStore, encryptionService encryption.Internal,
) *AlertNotificationService {
notificationService *notifications.NotificationService) *AlertNotificationService {
s := &AlertNotificationService{
Bus: bus,
SQLStore: store,
EncryptionService: encryptionService,
Bus: bus,
SQLStore: store,
EncryptionService: encryptionService,
NotificationService: notificationService,
}
s.Bus.AddHandler(s.GetAlertNotifications)
@ -153,7 +156,7 @@ func (s *AlertNotificationService) createNotifier(ctx context.Context, model *mo
return nil, err
}
notifier, err := InitNotifier(model, s.EncryptionService.GetDecryptedValue)
notifier, err := InitNotifier(model, s.EncryptionService.GetDecryptedValue, s.NotificationService)
if err != nil {
logger.Error("Failed to create notifier", "error", err.Error())
return nil, err

@ -8,6 +8,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/require"
@ -19,7 +20,7 @@ func TestService(t *testing.T) {
nType := "test"
registerTestNotifier(nType)
s := ProvideService(bus.New(), sqlStore, ossencryption.ProvideService())
s := ProvideService(bus.New(), sqlStore, ossencryption.ProvideService(), nil)
origSecret := setting.SecretKey
setting.SecretKey = "alert_notification_service_test"
@ -116,7 +117,9 @@ func TestService(t *testing.T) {
func registerTestNotifier(notifierType string) {
RegisterNotifier(&NotifierPlugin{
Type: notifierType,
Factory: func(*models.AlertNotification, GetDecryptedValueFn) (Notifier, error) { return nil, nil },
Type: notifierType,
Factory: func(*models.AlertNotification, GetDecryptedValueFn, notifications.Service) (Notifier, error) {
return nil, nil
},
})
}

@ -29,7 +29,7 @@ var (
)
func (s *AlertNotificationService) HandleNotificationTestCommand(ctx context.Context, cmd *NotificationTestCommand) error {
notificationSvc := newNotificationService(nil, nil)
notificationSvc := newNotificationService(nil, nil, nil, nil)
model := models.AlertNotification{
Id: cmd.ID,
@ -57,7 +57,7 @@ func createTestEvalContext(cmd *NotificationTestCommand) *EvalContext {
ID: rand.Int63(),
}
ctx := NewEvalContext(context.Background(), testRule, fakeRequestValidator{})
ctx := NewEvalContext(context.Background(), testRule, fakeRequestValidator{}, nil)
if cmd.Settings.Get("uploadImage").MustBool(true) {
ctx.ImagePublicURL = "https://grafana.com/assets/img/blog/mixed_styles.png"
}

@ -29,7 +29,7 @@ func (e *AlertEngine) AlertTest(orgID int64, dashboard *simplejson.Json, panelID
handler := NewEvalHandler(e.DataService)
context := NewEvalContext(context.Background(), rule, fakeRequestValidator{})
context := NewEvalContext(context.Background(), rule, fakeRequestValidator{}, nil)
context.IsTestRun = true
context.IsDebug = true

@ -5,12 +5,13 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/encryption"
"github.com/grafana/grafana/pkg/services/notifications"
"golang.org/x/net/context"
)
// Provision alert notifiers
func Provision(ctx context.Context, configDirectory string, encryptionService encryption.Internal) error {
dc := newNotificationProvisioner(encryptionService, log.New("provisioning.notifiers"))
func Provision(ctx context.Context, configDirectory string, encryptionService encryption.Internal, notificationService *notifications.NotificationService) error {
dc := newNotificationProvisioner(encryptionService, notificationService, log.New("provisioning.notifiers"))
return dc.applyChanges(ctx, configDirectory)
}
@ -20,12 +21,13 @@ type NotificationProvisioner struct {
cfgProvider *configReader
}
func newNotificationProvisioner(encryptionService encryption.Internal, log log.Logger) NotificationProvisioner {
func newNotificationProvisioner(encryptionService encryption.Internal, notifiationService *notifications.NotificationService, log log.Logger) NotificationProvisioner {
return NotificationProvisioner{
log: log,
cfgProvider: &configReader{
encryptionService: encryptionService,
log: log,
encryptionService: encryptionService,
notificationService: notifiationService,
log: log,
},
}
}

@ -12,14 +12,16 @@ import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/services/encryption"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/services/provisioning/utils"
"github.com/grafana/grafana/pkg/setting"
"gopkg.in/yaml.v2"
)
type configReader struct {
encryptionService encryption.Internal
log log.Logger
encryptionService encryption.Internal
notificationService *notifications.NotificationService
log log.Logger
}
func (cr *configReader) readConfig(ctx context.Context, path string) ([]*notificationsAsConfig, error) {
@ -175,7 +177,7 @@ func (cr *configReader) validateNotifications(notifications []*notificationsAsCo
Settings: notification.SettingsToJSON(),
SecureSettings: encryptedSecureSettings,
Type: notification.Type,
}, cr.encryptionService.GetDecryptedValue)
}, cr.encryptionService.GetDecryptedValue, cr.notificationService)
if err != nil {
return err

@ -139,7 +139,7 @@ func TestNotificationAsConfig(t *testing.T) {
t.Run("One configured notification", func(t *testing.T) {
t.Run("no notification in database", func(t *testing.T) {
setup()
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
dc := newNotificationProvisioner(ossencryption.ProvideService(), nil, logger)
err := dc.applyChanges(context.Background(), twoNotificationsConfig)
if err != nil {
@ -170,7 +170,7 @@ func TestNotificationAsConfig(t *testing.T) {
require.Equal(t, len(notificationsQuery.Result), 1)
t.Run("should update one notification", func(t *testing.T) {
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
dc := newNotificationProvisioner(ossencryption.ProvideService(), nil, logger)
err = dc.applyChanges(context.Background(), twoNotificationsConfig)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
@ -194,7 +194,7 @@ func TestNotificationAsConfig(t *testing.T) {
})
t.Run("Two notifications with is_default", func(t *testing.T) {
setup()
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
dc := newNotificationProvisioner(ossencryption.ProvideService(), nil, logger)
err := dc.applyChanges(context.Background(), doubleNotificationsConfig)
t.Run("should both be inserted", func(t *testing.T) {
require.NoError(t, err)
@ -237,7 +237,7 @@ func TestNotificationAsConfig(t *testing.T) {
require.Equal(t, len(notificationsQuery.Result), 2)
t.Run("should have two new notifications", func(t *testing.T) {
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
dc := newNotificationProvisioner(ossencryption.ProvideService(), nil, logger)
err := dc.applyChanges(context.Background(), twoNotificationsConfig)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
@ -271,7 +271,7 @@ func TestNotificationAsConfig(t *testing.T) {
err = sqlStore.CreateAlertNotificationCommand(context.Background(), &existingNotificationCmd)
require.NoError(t, err)
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
dc := newNotificationProvisioner(ossencryption.ProvideService(), nil, logger)
err = dc.applyChanges(context.Background(), correctPropertiesWithOrgName)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
@ -290,7 +290,7 @@ func TestNotificationAsConfig(t *testing.T) {
t.Run("Config doesn't contain required field", func(t *testing.T) {
setup()
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
dc := newNotificationProvisioner(ossencryption.ProvideService(), nil, logger)
err := dc.applyChanges(context.Background(), noRequiredFields)
require.NotNil(t, err)
@ -304,7 +304,7 @@ func TestNotificationAsConfig(t *testing.T) {
t.Run("Empty yaml file", func(t *testing.T) {
t.Run("should have not changed repo", func(t *testing.T) {
setup()
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
dc := newNotificationProvisioner(ossencryption.ProvideService(), nil, logger)
err := dc.applyChanges(context.Background(), emptyFile)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)

@ -9,6 +9,7 @@ import (
plugifaces "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/services/encryption"
"github.com/grafana/grafana/pkg/services/notifications"
"github.com/grafana/grafana/pkg/services/provisioning/dashboards"
"github.com/grafana/grafana/pkg/services/provisioning/datasources"
"github.com/grafana/grafana/pkg/services/provisioning/notifiers"
@ -19,12 +20,13 @@ import (
)
func ProvideService(cfg *setting.Cfg, sqlStore *sqlstore.SQLStore, pluginStore plugifaces.Store,
encryptionService encryption.Internal) (*ProvisioningServiceImpl, error) {
encryptionService encryption.Internal, notificatonService *notifications.NotificationService) (*ProvisioningServiceImpl, error) {
s := &ProvisioningServiceImpl{
Cfg: cfg,
SQLStore: sqlStore,
pluginStore: pluginStore,
EncryptionService: encryptionService,
NotificationService: notificatonService,
log: log.New("provisioning"),
newDashboardProvisioner: dashboards.New,
provisionNotifiers: notifiers.Provision,
@ -59,7 +61,7 @@ func NewProvisioningServiceImpl() *ProvisioningServiceImpl {
// Used for testing purposes
func newProvisioningServiceImpl(
newDashboardProvisioner dashboards.DashboardProvisionerFactory,
provisionNotifiers func(context.Context, string, encryption.Internal) error,
provisionNotifiers func(context.Context, string, encryption.Internal, *notifications.NotificationService) error,
provisionDatasources func(context.Context, string) error,
provisionPlugins func(context.Context, string, plugifaces.Store) error,
) *ProvisioningServiceImpl {
@ -77,11 +79,12 @@ type ProvisioningServiceImpl struct {
SQLStore *sqlstore.SQLStore
pluginStore plugifaces.Store
EncryptionService encryption.Internal
NotificationService *notifications.NotificationService
log log.Logger
pollingCtxCancel context.CancelFunc
newDashboardProvisioner dashboards.DashboardProvisionerFactory
dashboardProvisioner dashboards.DashboardProvisioner
provisionNotifiers func(context.Context, string, encryption.Internal) error
provisionNotifiers func(context.Context, string, encryption.Internal, *notifications.NotificationService) error
provisionDatasources func(context.Context, string) error
provisionPlugins func(context.Context, string, plugifaces.Store) error
mutex sync.Mutex
@ -157,7 +160,7 @@ func (ps *ProvisioningServiceImpl) ProvisionPlugins(ctx context.Context) error {
func (ps *ProvisioningServiceImpl) ProvisionNotifications(ctx context.Context) error {
alertNotificationsPath := filepath.Join(ps.Cfg.ProvisioningPath, "notifiers")
if err := ps.provisionNotifiers(ctx, alertNotificationsPath, ps.EncryptionService); err != nil {
if err := ps.provisionNotifiers(ctx, alertNotificationsPath, ps.EncryptionService, ps.NotificationService); err != nil {
err = errutil.Wrap("Alert notification provisioning error", err)
ps.log.Error("Failed to provision alert notifications", "error", err)
return err

@ -13,6 +13,22 @@ import (
"github.com/grafana/grafana/pkg/util"
)
type AlertNotificationStore interface {
DeleteAlertNotification(ctx context.Context, cmd *models.DeleteAlertNotificationCommand) error
DeleteAlertNotificationWithUid(ctx context.Context, cmd *models.DeleteAlertNotificationWithUidCommand) error
GetAlertNotifications(ctx context.Context, query *models.GetAlertNotificationsQuery) error
GetAlertNotificationUidWithId(ctx context.Context, query *models.GetAlertNotificationUidQuery) error
GetAlertNotificationsWithUid(ctx context.Context, query *models.GetAlertNotificationsWithUidQuery) error
GetAllAlertNotifications(ctx context.Context, query *models.GetAllAlertNotificationsQuery) error
GetAlertNotificationsWithUidToSend(ctx context.Context, query *models.GetAlertNotificationsWithUidToSendQuery) error
CreateAlertNotificationCommand(ctx context.Context, cmd *models.CreateAlertNotificationCommand) error
UpdateAlertNotification(ctx context.Context, cmd *models.UpdateAlertNotificationCommand) error
UpdateAlertNotificationWithUid(ctx context.Context, cmd *models.UpdateAlertNotificationWithUidCommand) error
SetAlertNotificationStateToCompleteCommand(ctx context.Context, cmd *models.SetAlertNotificationStateToCompleteCommand) error
SetAlertNotificationStateToPendingCommand(ctx context.Context, cmd *models.SetAlertNotificationStateToPendingCommand) error
GetOrCreateAlertNotificationState(ctx context.Context, cmd *models.GetOrCreateNotificationStateQuery) error
}
func (ss *SQLStore) DeleteAlertNotification(ctx context.Context, cmd *models.DeleteAlertNotificationCommand) error {
return ss.WithTransactionalDbSession(ctx, func(sess *DBSession) error {
sql := "DELETE FROM alert_notification WHERE alert_notification.org_id = ? AND alert_notification.id = ?"

@ -9,8 +9,9 @@ import (
)
type SQLStoreMock struct {
ExpectedUser *models.User
ExpectedError error
ExpectedUser *models.User
ExpectedDatasource *models.DataSource
ExpectedError error
}
func NewSQLStoreMock() *SQLStoreMock {
@ -18,83 +19,83 @@ func NewSQLStoreMock() *SQLStoreMock {
}
func (m SQLStoreMock) DeleteExpiredSnapshots(ctx context.Context, cmd *models.DeleteExpiredSnapshotsCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) CreateDashboardSnapshot(ctx context.Context, cmd *models.CreateDashboardSnapshotCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) DeleteDashboardSnapshot(ctx context.Context, cmd *models.DeleteDashboardSnapshotCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetDashboardSnapshot(query *models.GetDashboardSnapshotQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) SearchDashboardSnapshots(query *models.GetDashboardSnapshotsQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetOrgByName(name string) (*models.Org, error) {
return nil, nil // TODO: Implement
return nil, m.ExpectedError
}
func (m SQLStoreMock) CreateOrgWithMember(name string, userID int64) (models.Org, error) {
return models.Org{}, nil // TODO: Implement
return models.Org{}, nil
}
func (m SQLStoreMock) UpdateOrg(ctx context.Context, cmd *models.UpdateOrgCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateOrgAddress(ctx context.Context, cmd *models.UpdateOrgAddressCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) DeleteOrg(ctx context.Context, cmd *models.DeleteOrgCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetProvisionedDataByDashboardID(dashboardID int64) (*models.DashboardProvisioning, error) {
return nil, nil // TODO: Implement
return nil, m.ExpectedError
}
func (m SQLStoreMock) GetProvisionedDataByDashboardUID(orgID int64, dashboardUID string) (*models.DashboardProvisioning, error) {
return nil, nil // TODO: Implement
return nil, m.ExpectedError
}
func (m SQLStoreMock) SaveProvisionedDashboard(cmd models.SaveDashboardCommand, provisioning *models.DashboardProvisioning) (*models.Dashboard, error) {
return nil, nil // TODO: Implement
return nil, m.ExpectedError
}
func (m SQLStoreMock) GetProvisionedDashboardData(name string) ([]*models.DashboardProvisioning, error) {
return nil, nil // TODO: Implement
return nil, m.ExpectedError
}
func (m SQLStoreMock) DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *models.DeleteOrphanedProvisionedDashboardsCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) CreateLoginAttempt(ctx context.Context, cmd *models.CreateLoginAttemptCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) DeleteOldLoginAttempts(ctx context.Context, cmd *models.DeleteOldLoginAttemptsCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) CloneUserToServiceAccount(ctx context.Context, siUser *models.SignedInUser) (*models.User, error) {
return nil, nil // TODO: Implement
return nil, m.ExpectedError
}
func (m SQLStoreMock) CreateServiceAccountForApikey(ctx context.Context, orgId int64, keyname string, role models.RoleType) (*models.User, error) {
return nil, nil // TODO: Implement
return nil, m.ExpectedError
}
func (m SQLStoreMock) CreateUser(ctx context.Context, cmd models.CreateUserCommand) (*models.User, error) {
return nil, nil // TODO: Implement
return nil, m.ExpectedError
}
func (m SQLStoreMock) GetUserById(ctx context.Context, query *models.GetUserByIdQuery) error {
@ -103,51 +104,51 @@ func (m SQLStoreMock) GetUserById(ctx context.Context, query *models.GetUserById
}
func (m SQLStoreMock) GetUserByLogin(ctx context.Context, query *models.GetUserByLoginQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetUserByEmail(ctx context.Context, query *models.GetUserByEmailQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateUser(ctx context.Context, cmd *models.UpdateUserCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) ChangeUserPassword(ctx context.Context, cmd *models.ChangeUserPasswordCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateUserLastSeenAt(ctx context.Context, cmd *models.UpdateUserLastSeenAtCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) SetUsingOrg(ctx context.Context, cmd *models.SetUsingOrgCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetUserProfile(ctx context.Context, query *models.GetUserProfileQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetUserOrgList(ctx context.Context, query *models.GetUserOrgListQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetSignedInUserWithCacheCtx(ctx context.Context, query *models.GetSignedInUserQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetSignedInUser(ctx context.Context, query *models.GetSignedInUserQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) BatchDisableUsers(ctx context.Context, cmd *models.BatchDisableUsersCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) DeleteUser(ctx context.Context, cmd *models.DeleteUserCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateUserPermissions(userID int64, isAdmin bool) error {
@ -155,7 +156,7 @@ func (m SQLStoreMock) UpdateUserPermissions(userID int64, isAdmin bool) error {
}
func (m SQLStoreMock) SetUserHelpFlag(ctx context.Context, cmd *models.SetUserHelpFlagCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) CreateTeam(name string, email string, orgID int64) (models.Team, error) {
@ -167,409 +168,410 @@ func (m SQLStoreMock) CreateTeam(name string, email string, orgID int64) (models
}
func (m SQLStoreMock) UpdateTeam(ctx context.Context, cmd *models.UpdateTeamCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) DeleteTeam(ctx context.Context, cmd *models.DeleteTeamCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) SearchTeams(ctx context.Context, query *models.SearchTeamsQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetTeamById(ctx context.Context, query *models.GetTeamByIdQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetTeamsByUser(ctx context.Context, query *models.GetTeamsByUserQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) AddTeamMember(userID int64, orgID int64, teamID int64, isExternal bool, permission models.PermissionType) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateTeamMember(ctx context.Context, cmd *models.UpdateTeamMemberCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) IsTeamMember(orgId int64, teamId int64, userId int64) (bool, error) {
return false, nil // TODO: Implement
return false, nil
}
func (m SQLStoreMock) RemoveTeamMember(ctx context.Context, cmd *models.RemoveTeamMemberCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetTeamMembers(ctx context.Context, query *models.GetTeamMembersQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) NewSession(ctx context.Context) *sqlstore.DBSession {
return nil // TODO: Implement
return nil
}
func (m SQLStoreMock) WithDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetPreferencesWithDefaults(ctx context.Context, query *models.GetPreferencesWithDefaultsQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetPreferences(ctx context.Context, query *models.GetPreferencesQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) SavePreferences(ctx context.Context, cmd *models.SavePreferencesCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetPluginSettings(ctx context.Context, orgID int64) ([]*models.PluginSettingInfoDTO, error) {
return nil, nil // TODO: Implement
return nil, m.ExpectedError
}
func (m SQLStoreMock) GetPluginSettingById(ctx context.Context, query *models.GetPluginSettingByIdQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdatePluginSetting(ctx context.Context, cmd *models.UpdatePluginSettingCmd) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdatePluginSettingVersion(ctx context.Context, cmd *models.UpdatePluginSettingVersionCmd) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) IsStarredByUserCtx(ctx context.Context, query *models.IsStarredByUserQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) StarDashboard(ctx context.Context, cmd *models.StarDashboardCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UnstarDashboard(ctx context.Context, cmd *models.UnstarDashboardCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetUserStars(ctx context.Context, query *models.GetUserStarsQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetOrgQuotaByTarget(ctx context.Context, query *models.GetOrgQuotaByTargetQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetOrgQuotas(ctx context.Context, query *models.GetOrgQuotasQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateOrgQuota(ctx context.Context, cmd *models.UpdateOrgQuotaCmd) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetUserQuotaByTarget(ctx context.Context, query *models.GetUserQuotaByTargetQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetUserQuotas(ctx context.Context, query *models.GetUserQuotasQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateUserQuota(ctx context.Context, cmd *models.UpdateUserQuotaCmd) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetGlobalQuotaByTarget(ctx context.Context, query *models.GetGlobalQuotaByTargetQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) WithTransactionalDbSession(ctx context.Context, callback sqlstore.DBTransactionFunc) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) InTransaction(ctx context.Context, fn func(ctx context.Context) error) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetDashboardVersion(ctx context.Context, query *models.GetDashboardVersionQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetDashboardVersions(ctx context.Context, query *models.GetDashboardVersionsQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) DeleteExpiredVersions(ctx context.Context, cmd *models.DeleteExpiredVersionsCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateDashboardACL(ctx context.Context, dashboardID int64, items []*models.DashboardAcl) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateDashboardACLCtx(ctx context.Context, dashboardID int64, items []*models.DashboardAcl) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetDashboardAclInfoList(ctx context.Context, query *models.GetDashboardAclInfoListQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) CreatePlaylist(ctx context.Context, cmd *models.CreatePlaylistCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdatePlaylist(ctx context.Context, cmd *models.UpdatePlaylistCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetPlaylist(ctx context.Context, query *models.GetPlaylistByIdQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) DeletePlaylist(ctx context.Context, cmd *models.DeletePlaylistCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) SearchPlaylists(ctx context.Context, query *models.GetPlaylistsQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetPlaylistItem(ctx context.Context, query *models.GetPlaylistItemsByIdQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetAlertById(ctx context.Context, query *models.GetAlertByIdQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetAllAlertQueryHandler(ctx context.Context, query *models.GetAllAlertsQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) HandleAlertsQuery(ctx context.Context, query *models.GetAlertsQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) SaveAlerts(ctx context.Context, dashID int64, alerts []*models.Alert) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) SetAlertState(ctx context.Context, cmd *models.SetAlertStateCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) PauseAlert(ctx context.Context, cmd *models.PauseAlertCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) PauseAllAlerts(ctx context.Context, cmd *models.PauseAllAlertCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetAlertStatesForDashboard(ctx context.Context, query *models.GetAlertStatesForDashboardQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) AddOrgUser(ctx context.Context, cmd *models.AddOrgUserCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateOrgUser(ctx context.Context, cmd *models.UpdateOrgUserCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetOrgUsers(ctx context.Context, query *models.GetOrgUsersQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) SearchOrgUsers(ctx context.Context, query *models.SearchOrgUsersQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) RemoveOrgUser(ctx context.Context, cmd *models.RemoveOrgUserCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) SaveDashboard(cmd models.SaveDashboardCommand) (*models.Dashboard, error) {
return nil, nil // TODO: Implement
return nil, m.ExpectedError
}
func (m SQLStoreMock) GetDashboard(id int64, orgID int64, uid string, slug string) (*models.Dashboard, error) {
return nil, nil // TODO: Implement
return nil, m.ExpectedError
}
func (m SQLStoreMock) GetFolderByTitle(orgID int64, title string) (*models.Dashboard, error) {
return nil, nil // TODO: Implement
return nil, m.ExpectedError
}
func (m SQLStoreMock) SearchDashboards(ctx context.Context, query *search.FindPersistedDashboardsQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) DeleteDashboard(ctx context.Context, cmd *models.DeleteDashboardCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetDashboards(ctx context.Context, query *models.GetDashboardsQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetDashboardUIDById(ctx context.Context, query *models.GetDashboardRefByIdQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) ValidateDashboardBeforeSave(dashboard *models.Dashboard, overwrite bool) (bool, error) {
return false, nil // TODO: Implement
return false, nil
}
func (m SQLStoreMock) GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error {
return nil // TODO: Implement
query.Result = m.ExpectedDatasource
return m.ExpectedError
}
func (m SQLStoreMock) GetDataSources(ctx context.Context, query *models.GetDataSourcesQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetDataSourcesByType(ctx context.Context, query *models.GetDataSourcesByTypeQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetDefaultDataSource(ctx context.Context, query *models.GetDefaultDataSourceQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) DeleteDataSource(ctx context.Context, cmd *models.DeleteDataSourceCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) AddDataSource(ctx context.Context, cmd *models.AddDataSourceCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateDataSource(ctx context.Context, cmd *models.UpdateDataSourceCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) Migrate() error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) Sync() error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) Reset() error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) Quote(value string) string {
return "" // TODO: Implement
return ""
}
func (m SQLStoreMock) DeleteAlertNotification(ctx context.Context, cmd *models.DeleteAlertNotificationCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) DeleteAlertNotificationWithUid(ctx context.Context, cmd *models.DeleteAlertNotificationWithUidCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetAlertNotifications(ctx context.Context, query *models.GetAlertNotificationsQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetAlertNotificationUidWithId(ctx context.Context, query *models.GetAlertNotificationUidQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetAlertNotificationsWithUid(ctx context.Context, query *models.GetAlertNotificationsWithUidQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetAllAlertNotifications(ctx context.Context, query *models.GetAllAlertNotificationsQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetAlertNotificationsWithUidToSend(ctx context.Context, query *models.GetAlertNotificationsWithUidToSendQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) CreateAlertNotificationCommand(ctx context.Context, cmd *models.CreateAlertNotificationCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateAlertNotification(ctx context.Context, cmd *models.UpdateAlertNotificationCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateAlertNotificationWithUid(ctx context.Context, cmd *models.UpdateAlertNotificationWithUidCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) SetAlertNotificationStateToCompleteCommand(ctx context.Context, cmd *models.SetAlertNotificationStateToCompleteCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) SetAlertNotificationStateToPendingCommand(ctx context.Context, cmd *models.SetAlertNotificationStateToPendingCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetOrCreateAlertNotificationState(ctx context.Context, cmd *models.GetOrCreateNotificationStateQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetAPIKeys(ctx context.Context, query *models.GetApiKeysQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetNonServiceAccountAPIKeys(ctx context.Context) []*models.ApiKey {
return nil // TODO: Implement
return nil
}
func (m SQLStoreMock) DeleteApiKey(ctx context.Context, cmd *models.DeleteApiKeyCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) AddAPIKey(ctx context.Context, cmd *models.AddApiKeyCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateApikeyServiceAccount(ctx context.Context, apikeyId int64, saccountId int64) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetApiKeyById(ctx context.Context, query *models.GetApiKeyByIdQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetApiKeyByName(ctx context.Context, query *models.GetApiKeyByNameQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateTempUserStatus(ctx context.Context, cmd *models.UpdateTempUserStatusCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) CreateTempUser(ctx context.Context, cmd *models.CreateTempUserCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) UpdateTempUserWithEmailSent(ctx context.Context, cmd *models.UpdateTempUserWithEmailSentCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetTempUsersQuery(ctx context.Context, query *models.GetTempUsersQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) GetTempUserByCode(ctx context.Context, query *models.GetTempUserByCodeQuery) error {
return nil // TODO: Implement
return m.ExpectedError
}
func (m SQLStoreMock) ExpireOldUserInvites(ctx context.Context, cmd *models.ExpireTempUsersCommand) error {
return nil // TODO: Implement
return m.ExpectedError
}

Loading…
Cancel
Save