diff --git a/pkg/services/ngalert/api/api.go b/pkg/services/ngalert/api/api.go index ee691e7ca42..a3ea2c7e3a8 100644 --- a/pkg/services/ngalert/api/api.go +++ b/pkg/services/ngalert/api/api.go @@ -32,8 +32,8 @@ type Scheduler interface { type Alertmanager interface { // Configuration - SaveAndApplyConfig(config *apimodels.PostableUserConfig) error - SaveAndApplyDefaultConfig() error + SaveAndApplyConfig(ctx context.Context, config *apimodels.PostableUserConfig) error + SaveAndApplyDefaultConfig(ctx context.Context) error GetStatus() apimodels.GettableStatus // Silences @@ -51,7 +51,7 @@ type Alertmanager interface { } type AlertingStore interface { - GetLatestAlertmanagerConfiguration(query *models.GetLatestAlertmanagerConfigurationQuery) error + GetLatestAlertmanagerConfiguration(ctx context.Context, query *models.GetLatestAlertmanagerConfigurationQuery) error } // API handlers. diff --git a/pkg/services/ngalert/api/api_alertmanager.go b/pkg/services/ngalert/api/api_alertmanager.go index 6cd51940498..b04b21cd2e5 100644 --- a/pkg/services/ngalert/api/api_alertmanager.go +++ b/pkg/services/ngalert/api/api_alertmanager.go @@ -42,10 +42,10 @@ func (e UnknownReceiverError) Error() string { 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 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 !errors.Is(err, store.ErrNoAlertmanagerConfiguration) { return fmt.Errorf("failed to get latest configuration: %w", err) @@ -159,7 +159,7 @@ func (srv AlertmanagerSrv) RouteDeleteAlertingConfig(c *models.ReqContext) respo 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) 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} - 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) { return ErrResp(http.StatusNotFound, err, "") } @@ -340,14 +340,14 @@ func (srv AlertmanagerSrv) RoutePostAlertingConfig(c *models.ReqContext, body ap // Get the last known working configuration 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 !errors.Is(err, store.ErrNoAlertmanagerConfiguration) { 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 if errors.As(err, &unknownReceiverError) { 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) 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() } - 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 if errors.As(err, &unknownReceiverError) { return ErrResp(http.StatusBadRequest, err, "") diff --git a/pkg/services/ngalert/api/api_alertmanager_test.go b/pkg/services/ngalert/api/api_alertmanager_test.go index 479dfb75828..0e88ddc4542 100644 --- a/pkg/services/ngalert/api/api_alertmanager_test.go +++ b/pkg/services/ngalert/api/api_alertmanager_test.go @@ -17,6 +17,7 @@ import ( "github.com/grafana/grafana/pkg/services/secrets/fakes" secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager" "github.com/grafana/grafana/pkg/setting" + "github.com/grafana/grafana/pkg/web" "github.com/prometheus/client_golang/prometheus" "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) { rc := models.ReqContext{ + Context: &web.Context{ + Req: &http.Request{}, + }, SignedInUser: &models.SignedInUser{ OrgRole: models.ROLE_EDITOR, 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) { rc := models.ReqContext{ + Context: &web.Context{ + Req: &http.Request{}, + }, SignedInUser: &models.SignedInUser{ OrgRole: models.ROLE_VIEWER, OrgId: 1, @@ -185,6 +192,9 @@ func TestAlertmanagerConfig(t *testing.T) { t.Run("assert 202 when config successfully applied", func(t *testing.T) { rc := models.ReqContext{ + Context: &web.Context{ + Req: &http.Request{}, + }, SignedInUser: &models.SignedInUser{ OrgRole: models.ROLE_EDITOR, 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) { sut := createSut(t) rc := models.ReqContext{ + Context: &web.Context{ + Req: &http.Request{}, + }, SignedInUser: &models.SignedInUser{ OrgRole: models.ROLE_EDITOR, OrgId: 3, // Org 3 was initialized with broken config. diff --git a/pkg/services/ngalert/api/testing.go b/pkg/services/ngalert/api/testing.go index 0a87897f913..398399fe768 100644 --- a/pkg/services/ngalert/api/testing.go +++ b/pkg/services/ngalert/api/testing.go @@ -1,6 +1,7 @@ package api import ( + "context" "testing" "github.com/grafana/grafana/pkg/services/ngalert/models" @@ -23,7 +24,7 @@ func (f FakeAlertingStore) Setup(orgID int64) { 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 { return nil } diff --git a/pkg/services/ngalert/notifier/alertmanager.go b/pkg/services/ngalert/notifier/alertmanager.go index ec74131a01b..2ebe423be3b 100644 --- a/pkg/services/ngalert/notifier/alertmanager.go +++ b/pkg/services/ngalert/notifier/alertmanager.go @@ -232,7 +232,7 @@ func (am *Alertmanager) StopAndWait() { // 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. -func (am *Alertmanager) SaveAndApplyDefaultConfig() error { +func (am *Alertmanager) SaveAndApplyDefaultConfig(ctx context.Context) error { am.reloadConfigMtx.Lock() defer am.reloadConfigMtx.Unlock() @@ -248,7 +248,7 @@ func (am *Alertmanager) SaveAndApplyDefaultConfig() error { 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 { return err } @@ -263,7 +263,7 @@ func (am *Alertmanager) SaveAndApplyDefaultConfig() error { // SaveAndApplyConfig saves the configuration the database and applies the configuration to the Alertmanager. // 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) if err != nil { 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, } - err = am.Store.SaveAlertmanagerConfigurationWithCallback(cmd, func() error { + err = am.Store.SaveAlertmanagerConfigurationWithCallback(ctx, cmd, func() error { if err := am.applyConfig(cfg, rawConfig); err != nil { return err } diff --git a/pkg/services/ngalert/notifier/multiorg_alertmanager.go b/pkg/services/ngalert/notifier/multiorg_alertmanager.go index c2e48151eba..3c8a2f1d987 100644 --- a/pkg/services/ngalert/notifier/multiorg_alertmanager.go +++ b/pkg/services/ngalert/notifier/multiorg_alertmanager.go @@ -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. 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 { moa.logger.Error("failed to apply the default Alertmanager configuration", "org", orgID) continue diff --git a/pkg/services/ngalert/notifier/testing.go b/pkg/services/ngalert/notifier/testing.go index e478bfbae50..e89ce32e6a3 100644 --- a/pkg/services/ngalert/notifier/testing.go +++ b/pkg/services/ngalert/notifier/testing.go @@ -31,7 +31,7 @@ func (f *FakeConfigStore) GetAllLatestAlertmanagerConfiguration(context.Context) return result, nil } -func (f *FakeConfigStore) GetLatestAlertmanagerConfiguration(query *models.GetLatestAlertmanagerConfigurationQuery) error { +func (f *FakeConfigStore) GetLatestAlertmanagerConfiguration(_ context.Context, query *models.GetLatestAlertmanagerConfigurationQuery) error { var ok bool query.Result, ok = f.configs[query.OrgID] if !ok { @@ -41,7 +41,7 @@ func (f *FakeConfigStore) GetLatestAlertmanagerConfiguration(query *models.GetLa 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{ AlertmanagerConfiguration: cmd.AlertmanagerConfiguration, OrgID: cmd.OrgID, @@ -52,7 +52,7 @@ func (f *FakeConfigStore) SaveAlertmanagerConfiguration(cmd *models.SaveAlertman 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{ AlertmanagerConfiguration: cmd.AlertmanagerConfiguration, OrgID: cmd.OrgID, diff --git a/pkg/services/ngalert/store/alertmanager.go b/pkg/services/ngalert/store/alertmanager.go index 5f979e69f26..0edc09b7974 100644 --- a/pkg/services/ngalert/store/alertmanager.go +++ b/pkg/services/ngalert/store/alertmanager.go @@ -17,8 +17,8 @@ var ( // GetLatestAlertmanagerConfiguration returns the lastest version of the alertmanager configuration. // It returns ErrNoAlertmanagerConfiguration if no configuration is found. -func (st *DBstore) GetLatestAlertmanagerConfiguration(query *models.GetLatestAlertmanagerConfigurationQuery) error { - return st.SQLStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error { +func (st *DBstore) GetLatestAlertmanagerConfiguration(ctx context.Context, query *models.GetLatestAlertmanagerConfigurationQuery) error { + return st.SQLStore.WithDbSession(ctx, func(sess *sqlstore.DBSession) error { c := &models.AlertConfiguration{} // 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) @@ -52,16 +52,16 @@ func (st *DBstore) GetAllLatestAlertmanagerConfiguration(ctx context.Context) ([ } // SaveAlertmanagerConfiguration creates an alertmanager configuration. -func (st DBstore) SaveAlertmanagerConfiguration(cmd *models.SaveAlertmanagerConfigurationCmd) error { - return st.SaveAlertmanagerConfigurationWithCallback(cmd, func() error { return nil }) +func (st DBstore) SaveAlertmanagerConfiguration(ctx context.Context, cmd *models.SaveAlertmanagerConfigurationCmd) error { + return st.SaveAlertmanagerConfigurationWithCallback(ctx, cmd, func() error { return nil }) } type SaveCallback func() error // SaveAlertmanagerConfigurationWithCallback creates an alertmanager configuration version and then executes a callback. // If the callback results in error it rolls back the transaction. -func (st DBstore) SaveAlertmanagerConfigurationWithCallback(cmd *models.SaveAlertmanagerConfigurationCmd, callback SaveCallback) error { - return st.SQLStore.WithTransactionalDbSession(context.Background(), func(sess *sqlstore.DBSession) error { +func (st DBstore) SaveAlertmanagerConfigurationWithCallback(ctx context.Context, cmd *models.SaveAlertmanagerConfigurationCmd, callback SaveCallback) error { + return st.SQLStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error { config := models.AlertConfiguration{ AlertmanagerConfiguration: cmd.AlertmanagerConfiguration, ConfigurationVersion: cmd.ConfigurationVersion, diff --git a/pkg/services/ngalert/store/database.go b/pkg/services/ngalert/store/database.go index 3503d34c4c9..7a6505704e7 100644 --- a/pkg/services/ngalert/store/database.go +++ b/pkg/services/ngalert/store/database.go @@ -17,10 +17,10 @@ const AlertDefinitionMaxTitleLength = 190 // AlertingStore is the database interface used by the Alertmanager service. type AlertingStore interface { - GetLatestAlertmanagerConfiguration(*models.GetLatestAlertmanagerConfigurationQuery) error + GetLatestAlertmanagerConfiguration(ctx context.Context, query *models.GetLatestAlertmanagerConfigurationQuery) error GetAllLatestAlertmanagerConfiguration(ctx context.Context) ([]*models.AlertConfiguration, error) - SaveAlertmanagerConfiguration(*models.SaveAlertmanagerConfigurationCmd) error - SaveAlertmanagerConfigurationWithCallback(*models.SaveAlertmanagerConfigurationCmd, SaveCallback) error + SaveAlertmanagerConfiguration(ctx context.Context, cmd *models.SaveAlertmanagerConfigurationCmd) error + SaveAlertmanagerConfigurationWithCallback(ctx context.Context, cmd *models.SaveAlertmanagerConfigurationCmd, callback SaveCallback) error } // DBstore stores the alert definitions and instances in the database.