Add context.Context to AlertingStore (#45069)

pull/45134/head
George Robinson 3 years ago committed by GitHub
parent 069f772c6f
commit 4e3a72fc2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      pkg/services/ngalert/api/api.go
  2. 16
      pkg/services/ngalert/api/api_alertmanager.go
  3. 13
      pkg/services/ngalert/api/api_alertmanager_test.go
  4. 3
      pkg/services/ngalert/api/testing.go
  5. 8
      pkg/services/ngalert/notifier/alertmanager.go
  6. 2
      pkg/services/ngalert/notifier/multiorg_alertmanager.go
  7. 6
      pkg/services/ngalert/notifier/testing.go
  8. 12
      pkg/services/ngalert/store/alertmanager.go
  9. 6
      pkg/services/ngalert/store/database.go

@ -32,8 +32,8 @@ type Scheduler interface {
type Alertmanager interface { type Alertmanager interface {
// Configuration // Configuration
SaveAndApplyConfig(config *apimodels.PostableUserConfig) error SaveAndApplyConfig(ctx context.Context, config *apimodels.PostableUserConfig) error
SaveAndApplyDefaultConfig() error SaveAndApplyDefaultConfig(ctx context.Context) error
GetStatus() apimodels.GettableStatus GetStatus() apimodels.GettableStatus
// Silences // Silences
@ -51,7 +51,7 @@ type Alertmanager interface {
} }
type AlertingStore interface { type AlertingStore interface {
GetLatestAlertmanagerConfiguration(query *models.GetLatestAlertmanagerConfigurationQuery) error GetLatestAlertmanagerConfiguration(ctx context.Context, query *models.GetLatestAlertmanagerConfigurationQuery) error
} }
// API handlers. // API handlers.

@ -42,10 +42,10 @@ func (e UnknownReceiverError) Error() string {
return fmt.Sprintf("unknown receiver: %s", e.UID) return fmt.Sprintf("unknown receiver: %s", e.UID)
} }
func (srv AlertmanagerSrv) loadSecureSettings(orgId int64, receivers []*apimodels.PostableApiReceiver) error { func (srv AlertmanagerSrv) loadSecureSettings(ctx context.Context, orgId int64, receivers []*apimodels.PostableApiReceiver) error {
// Get the last known working configuration // Get the last known working configuration
query := ngmodels.GetLatestAlertmanagerConfigurationQuery{OrgID: orgId} query := ngmodels.GetLatestAlertmanagerConfigurationQuery{OrgID: orgId}
if err := srv.store.GetLatestAlertmanagerConfiguration(&query); err != nil { if err := srv.store.GetLatestAlertmanagerConfiguration(ctx, &query); err != nil {
// If we don't have a configuration there's nothing for us to know and we should just continue saving the new one // If we don't have a configuration there's nothing for us to know and we should just continue saving the new one
if !errors.Is(err, store.ErrNoAlertmanagerConfiguration) { if !errors.Is(err, store.ErrNoAlertmanagerConfiguration) {
return fmt.Errorf("failed to get latest configuration: %w", err) return fmt.Errorf("failed to get latest configuration: %w", err)
@ -159,7 +159,7 @@ func (srv AlertmanagerSrv) RouteDeleteAlertingConfig(c *models.ReqContext) respo
return errResp return errResp
} }
if err := am.SaveAndApplyDefaultConfig(); err != nil { if err := am.SaveAndApplyDefaultConfig(c.Req.Context()); err != nil {
srv.log.Error("unable to save and apply default alertmanager configuration", "err", err) srv.log.Error("unable to save and apply default alertmanager configuration", "err", err)
return ErrResp(http.StatusInternalServerError, err, "failed to save and apply default Alertmanager configuration") return ErrResp(http.StatusInternalServerError, err, "failed to save and apply default Alertmanager configuration")
} }
@ -193,7 +193,7 @@ func (srv AlertmanagerSrv) RouteGetAlertingConfig(c *models.ReqContext) response
} }
query := ngmodels.GetLatestAlertmanagerConfigurationQuery{OrgID: c.OrgId} query := ngmodels.GetLatestAlertmanagerConfigurationQuery{OrgID: c.OrgId}
if err := srv.store.GetLatestAlertmanagerConfiguration(&query); err != nil { if err := srv.store.GetLatestAlertmanagerConfiguration(c.Req.Context(), &query); err != nil {
if errors.Is(err, store.ErrNoAlertmanagerConfiguration) { if errors.Is(err, store.ErrNoAlertmanagerConfiguration) {
return ErrResp(http.StatusNotFound, err, "") return ErrResp(http.StatusNotFound, err, "")
} }
@ -340,14 +340,14 @@ func (srv AlertmanagerSrv) RoutePostAlertingConfig(c *models.ReqContext, body ap
// Get the last known working configuration // Get the last known working configuration
query := ngmodels.GetLatestAlertmanagerConfigurationQuery{OrgID: c.OrgId} query := ngmodels.GetLatestAlertmanagerConfigurationQuery{OrgID: c.OrgId}
if err := srv.store.GetLatestAlertmanagerConfiguration(&query); err != nil { if err := srv.store.GetLatestAlertmanagerConfiguration(c.Req.Context(), &query); err != nil {
// If we don't have a configuration there's nothing for us to know and we should just continue saving the new one // If we don't have a configuration there's nothing for us to know and we should just continue saving the new one
if !errors.Is(err, store.ErrNoAlertmanagerConfiguration) { if !errors.Is(err, store.ErrNoAlertmanagerConfiguration) {
return ErrResp(http.StatusInternalServerError, err, "failed to get latest configuration") return ErrResp(http.StatusInternalServerError, err, "failed to get latest configuration")
} }
} }
if err := srv.loadSecureSettings(c.OrgId, body.AlertmanagerConfig.Receivers); err != nil { if err := srv.loadSecureSettings(c.Req.Context(), c.OrgId, body.AlertmanagerConfig.Receivers); err != nil {
var unknownReceiverError UnknownReceiverError var unknownReceiverError UnknownReceiverError
if errors.As(err, &unknownReceiverError) { if errors.As(err, &unknownReceiverError) {
return ErrResp(http.StatusBadRequest, err, "") return ErrResp(http.StatusBadRequest, err, "")
@ -367,7 +367,7 @@ func (srv AlertmanagerSrv) RoutePostAlertingConfig(c *models.ReqContext, body ap
} }
} }
if err := am.SaveAndApplyConfig(&body); err != nil { if err := am.SaveAndApplyConfig(c.Req.Context(), &body); err != nil {
srv.log.Error("unable to save and apply alertmanager configuration", "err", err) srv.log.Error("unable to save and apply alertmanager configuration", "err", err)
return ErrResp(http.StatusBadRequest, err, "failed to save and apply Alertmanager configuration") return ErrResp(http.StatusBadRequest, err, "failed to save and apply Alertmanager configuration")
} }
@ -384,7 +384,7 @@ func (srv AlertmanagerSrv) RoutePostTestReceivers(c *models.ReqContext, body api
return accessForbiddenResp() return accessForbiddenResp()
} }
if err := srv.loadSecureSettings(c.OrgId, body.Receivers); err != nil { if err := srv.loadSecureSettings(c.Req.Context(), c.OrgId, body.Receivers); err != nil {
var unknownReceiverError UnknownReceiverError var unknownReceiverError UnknownReceiverError
if errors.As(err, &unknownReceiverError) { if errors.As(err, &unknownReceiverError) {
return ErrResp(http.StatusBadRequest, err, "") return ErrResp(http.StatusBadRequest, err, "")

@ -17,6 +17,7 @@ import (
"github.com/grafana/grafana/pkg/services/secrets/fakes" "github.com/grafana/grafana/pkg/services/secrets/fakes"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -155,6 +156,9 @@ func TestAlertmanagerConfig(t *testing.T) {
t.Run("assert 404 Not Found when applying config to nonexistent org", func(t *testing.T) { t.Run("assert 404 Not Found when applying config to nonexistent org", func(t *testing.T) {
rc := models.ReqContext{ rc := models.ReqContext{
Context: &web.Context{
Req: &http.Request{},
},
SignedInUser: &models.SignedInUser{ SignedInUser: &models.SignedInUser{
OrgRole: models.ROLE_EDITOR, OrgRole: models.ROLE_EDITOR,
OrgId: 12, OrgId: 12,
@ -170,6 +174,9 @@ func TestAlertmanagerConfig(t *testing.T) {
t.Run("assert 403 Forbidden when applying config while not Editor", func(t *testing.T) { t.Run("assert 403 Forbidden when applying config while not Editor", func(t *testing.T) {
rc := models.ReqContext{ rc := models.ReqContext{
Context: &web.Context{
Req: &http.Request{},
},
SignedInUser: &models.SignedInUser{ SignedInUser: &models.SignedInUser{
OrgRole: models.ROLE_VIEWER, OrgRole: models.ROLE_VIEWER,
OrgId: 1, OrgId: 1,
@ -185,6 +192,9 @@ func TestAlertmanagerConfig(t *testing.T) {
t.Run("assert 202 when config successfully applied", func(t *testing.T) { t.Run("assert 202 when config successfully applied", func(t *testing.T) {
rc := models.ReqContext{ rc := models.ReqContext{
Context: &web.Context{
Req: &http.Request{},
},
SignedInUser: &models.SignedInUser{ SignedInUser: &models.SignedInUser{
OrgRole: models.ROLE_EDITOR, OrgRole: models.ROLE_EDITOR,
OrgId: 1, OrgId: 1,
@ -200,6 +210,9 @@ func TestAlertmanagerConfig(t *testing.T) {
t.Run("assert 202 when alertmanager to configure is not ready", func(t *testing.T) { t.Run("assert 202 when alertmanager to configure is not ready", func(t *testing.T) {
sut := createSut(t) sut := createSut(t)
rc := models.ReqContext{ rc := models.ReqContext{
Context: &web.Context{
Req: &http.Request{},
},
SignedInUser: &models.SignedInUser{ SignedInUser: &models.SignedInUser{
OrgRole: models.ROLE_EDITOR, OrgRole: models.ROLE_EDITOR,
OrgId: 3, // Org 3 was initialized with broken config. OrgId: 3, // Org 3 was initialized with broken config.

@ -1,6 +1,7 @@
package api package api
import ( import (
"context"
"testing" "testing"
"github.com/grafana/grafana/pkg/services/ngalert/models" "github.com/grafana/grafana/pkg/services/ngalert/models"
@ -23,7 +24,7 @@ func (f FakeAlertingStore) Setup(orgID int64) {
f.orgsWithConfig[orgID] = true f.orgsWithConfig[orgID] = true
} }
func (f FakeAlertingStore) GetLatestAlertmanagerConfiguration(query *models.GetLatestAlertmanagerConfigurationQuery) error { func (f FakeAlertingStore) GetLatestAlertmanagerConfiguration(_ context.Context, query *models.GetLatestAlertmanagerConfigurationQuery) error {
if _, ok := f.orgsWithConfig[query.OrgID]; ok { if _, ok := f.orgsWithConfig[query.OrgID]; ok {
return nil return nil
} }

@ -232,7 +232,7 @@ func (am *Alertmanager) StopAndWait() {
// SaveAndApplyDefaultConfig saves the default configuration the database and applies the configuration to the Alertmanager. // SaveAndApplyDefaultConfig saves the default configuration the database and applies the configuration to the Alertmanager.
// It rollbacks the save if we fail to apply the configuration. // It rollbacks the save if we fail to apply the configuration.
func (am *Alertmanager) SaveAndApplyDefaultConfig() error { func (am *Alertmanager) SaveAndApplyDefaultConfig(ctx context.Context) error {
am.reloadConfigMtx.Lock() am.reloadConfigMtx.Lock()
defer am.reloadConfigMtx.Unlock() defer am.reloadConfigMtx.Unlock()
@ -248,7 +248,7 @@ func (am *Alertmanager) SaveAndApplyDefaultConfig() error {
return err return err
} }
err = am.Store.SaveAlertmanagerConfigurationWithCallback(cmd, func() error { err = am.Store.SaveAlertmanagerConfigurationWithCallback(ctx, cmd, func() error {
if err := am.applyConfig(cfg, []byte(am.Settings.UnifiedAlerting.DefaultConfiguration)); err != nil { if err := am.applyConfig(cfg, []byte(am.Settings.UnifiedAlerting.DefaultConfiguration)); err != nil {
return err return err
} }
@ -263,7 +263,7 @@ func (am *Alertmanager) SaveAndApplyDefaultConfig() error {
// SaveAndApplyConfig saves the configuration the database and applies the configuration to the Alertmanager. // SaveAndApplyConfig saves the configuration the database and applies the configuration to the Alertmanager.
// It rollbacks the save if we fail to apply the configuration. // It rollbacks the save if we fail to apply the configuration.
func (am *Alertmanager) SaveAndApplyConfig(cfg *apimodels.PostableUserConfig) error { func (am *Alertmanager) SaveAndApplyConfig(ctx context.Context, cfg *apimodels.PostableUserConfig) error {
rawConfig, err := json.Marshal(&cfg) rawConfig, err := json.Marshal(&cfg)
if err != nil { if err != nil {
return fmt.Errorf("failed to serialize to the Alertmanager configuration: %w", err) return fmt.Errorf("failed to serialize to the Alertmanager configuration: %w", err)
@ -278,7 +278,7 @@ func (am *Alertmanager) SaveAndApplyConfig(cfg *apimodels.PostableUserConfig) er
OrgID: am.orgID, OrgID: am.orgID,
} }
err = am.Store.SaveAlertmanagerConfigurationWithCallback(cmd, func() error { err = am.Store.SaveAlertmanagerConfigurationWithCallback(ctx, cmd, func() error {
if err := am.applyConfig(cfg, rawConfig); err != nil { if err := am.applyConfig(cfg, rawConfig); err != nil {
return err return err
} }

@ -188,7 +188,7 @@ func (moa *MultiOrgAlertmanager) SyncAlertmanagersForOrgs(ctx context.Context, o
// This means that the configuration is gone but the organization, as well as the Alertmanager, exists. // This means that the configuration is gone but the organization, as well as the Alertmanager, exists.
moa.logger.Warn("Alertmanager exists for org but the configuration is gone. Applying the default configuration", "org", orgID) moa.logger.Warn("Alertmanager exists for org but the configuration is gone. Applying the default configuration", "org", orgID)
} }
err := alertmanager.SaveAndApplyDefaultConfig() err := alertmanager.SaveAndApplyDefaultConfig(ctx)
if err != nil { if err != nil {
moa.logger.Error("failed to apply the default Alertmanager configuration", "org", orgID) moa.logger.Error("failed to apply the default Alertmanager configuration", "org", orgID)
continue continue

@ -31,7 +31,7 @@ func (f *FakeConfigStore) GetAllLatestAlertmanagerConfiguration(context.Context)
return result, nil return result, nil
} }
func (f *FakeConfigStore) GetLatestAlertmanagerConfiguration(query *models.GetLatestAlertmanagerConfigurationQuery) error { func (f *FakeConfigStore) GetLatestAlertmanagerConfiguration(_ context.Context, query *models.GetLatestAlertmanagerConfigurationQuery) error {
var ok bool var ok bool
query.Result, ok = f.configs[query.OrgID] query.Result, ok = f.configs[query.OrgID]
if !ok { if !ok {
@ -41,7 +41,7 @@ func (f *FakeConfigStore) GetLatestAlertmanagerConfiguration(query *models.GetLa
return nil return nil
} }
func (f *FakeConfigStore) SaveAlertmanagerConfiguration(cmd *models.SaveAlertmanagerConfigurationCmd) error { func (f *FakeConfigStore) SaveAlertmanagerConfiguration(_ context.Context, cmd *models.SaveAlertmanagerConfigurationCmd) error {
f.configs[cmd.OrgID] = &models.AlertConfiguration{ f.configs[cmd.OrgID] = &models.AlertConfiguration{
AlertmanagerConfiguration: cmd.AlertmanagerConfiguration, AlertmanagerConfiguration: cmd.AlertmanagerConfiguration,
OrgID: cmd.OrgID, OrgID: cmd.OrgID,
@ -52,7 +52,7 @@ func (f *FakeConfigStore) SaveAlertmanagerConfiguration(cmd *models.SaveAlertman
return nil return nil
} }
func (f *FakeConfigStore) SaveAlertmanagerConfigurationWithCallback(cmd *models.SaveAlertmanagerConfigurationCmd, callback store.SaveCallback) error { func (f *FakeConfigStore) SaveAlertmanagerConfigurationWithCallback(_ context.Context, cmd *models.SaveAlertmanagerConfigurationCmd, callback store.SaveCallback) error {
f.configs[cmd.OrgID] = &models.AlertConfiguration{ f.configs[cmd.OrgID] = &models.AlertConfiguration{
AlertmanagerConfiguration: cmd.AlertmanagerConfiguration, AlertmanagerConfiguration: cmd.AlertmanagerConfiguration,
OrgID: cmd.OrgID, OrgID: cmd.OrgID,

@ -17,8 +17,8 @@ var (
// GetLatestAlertmanagerConfiguration returns the lastest version of the alertmanager configuration. // GetLatestAlertmanagerConfiguration returns the lastest version of the alertmanager configuration.
// It returns ErrNoAlertmanagerConfiguration if no configuration is found. // It returns ErrNoAlertmanagerConfiguration if no configuration is found.
func (st *DBstore) GetLatestAlertmanagerConfiguration(query *models.GetLatestAlertmanagerConfigurationQuery) error { func (st *DBstore) GetLatestAlertmanagerConfiguration(ctx context.Context, query *models.GetLatestAlertmanagerConfigurationQuery) error {
return st.SQLStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error { return st.SQLStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error {
c := &models.AlertConfiguration{} c := &models.AlertConfiguration{}
// The ID is already an auto incremental column, using the ID as an order should guarantee the latest. // The ID is already an auto incremental column, using the ID as an order should guarantee the latest.
ok, err := sess.Desc("id").Where("org_id = ?", query.OrgID).Limit(1).Get(c) ok, err := sess.Desc("id").Where("org_id = ?", query.OrgID).Limit(1).Get(c)
@ -52,16 +52,16 @@ func (st *DBstore) GetAllLatestAlertmanagerConfiguration(ctx context.Context) ([
} }
// SaveAlertmanagerConfiguration creates an alertmanager configuration. // SaveAlertmanagerConfiguration creates an alertmanager configuration.
func (st DBstore) SaveAlertmanagerConfiguration(cmd *models.SaveAlertmanagerConfigurationCmd) error { func (st DBstore) SaveAlertmanagerConfiguration(ctx context.Context, cmd *models.SaveAlertmanagerConfigurationCmd) error {
return st.SaveAlertmanagerConfigurationWithCallback(cmd, func() error { return nil }) return st.SaveAlertmanagerConfigurationWithCallback(ctx, cmd, func() error { return nil })
} }
type SaveCallback func() error type SaveCallback func() error
// SaveAlertmanagerConfigurationWithCallback creates an alertmanager configuration version and then executes a callback. // SaveAlertmanagerConfigurationWithCallback creates an alertmanager configuration version and then executes a callback.
// If the callback results in error it rolls back the transaction. // If the callback results in error it rolls back the transaction.
func (st DBstore) SaveAlertmanagerConfigurationWithCallback(cmd *models.SaveAlertmanagerConfigurationCmd, callback SaveCallback) error { func (st DBstore) SaveAlertmanagerConfigurationWithCallback(ctx context.Context, cmd *models.SaveAlertmanagerConfigurationCmd, callback SaveCallback) error {
return st.SQLStore.WithTransactionalDbSession(context.Background(), func(sess *sqlstore.DBSession) error { return st.SQLStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
config := models.AlertConfiguration{ config := models.AlertConfiguration{
AlertmanagerConfiguration: cmd.AlertmanagerConfiguration, AlertmanagerConfiguration: cmd.AlertmanagerConfiguration,
ConfigurationVersion: cmd.ConfigurationVersion, ConfigurationVersion: cmd.ConfigurationVersion,

@ -17,10 +17,10 @@ const AlertDefinitionMaxTitleLength = 190
// AlertingStore is the database interface used by the Alertmanager service. // AlertingStore is the database interface used by the Alertmanager service.
type AlertingStore interface { type AlertingStore interface {
GetLatestAlertmanagerConfiguration(*models.GetLatestAlertmanagerConfigurationQuery) error GetLatestAlertmanagerConfiguration(ctx context.Context, query *models.GetLatestAlertmanagerConfigurationQuery) error
GetAllLatestAlertmanagerConfiguration(ctx context.Context) ([]*models.AlertConfiguration, error) GetAllLatestAlertmanagerConfiguration(ctx context.Context) ([]*models.AlertConfiguration, error)
SaveAlertmanagerConfiguration(*models.SaveAlertmanagerConfigurationCmd) error SaveAlertmanagerConfiguration(ctx context.Context, cmd *models.SaveAlertmanagerConfigurationCmd) error
SaveAlertmanagerConfigurationWithCallback(*models.SaveAlertmanagerConfigurationCmd, SaveCallback) error SaveAlertmanagerConfigurationWithCallback(ctx context.Context, cmd *models.SaveAlertmanagerConfigurationCmd, callback SaveCallback) error
} }
// DBstore stores the alert definitions and instances in the database. // DBstore stores the alert definitions and instances in the database.

Loading…
Cancel
Save