Alerting: modify DB table, accessors and migration to restrict org access (#37414)

* Alerting: modify table and accessors to limit org access appropriately

* Update migration to create multiple Alertmanager configs

* Apply suggestions from code review

Co-authored-by: gotjosh <josue@grafana.com>

* replace mg.ClearMigrationEntry()

mg.ClearMigrationEntry() would create a new session.
This commit introduces a new migration for clearing an entry from migration log for replacing  mg.ClearMigrationEntry() so that all dashboard alert migration operations will run inside the same transaction.
It adds also `SkipMigrationLog()` in Migrator interface for skipping adding an entry in the migration_log.

Co-authored-by: gotjosh <josue@grafana.com>
This commit is contained in:
Sofia Papagiannaki
2021-08-12 16:04:09 +03:00
committed by GitHub
co-authored by gotjosh
parent 4a9fdb8b76
commit 04d5dcb7c8
22 changed files with 460 additions and 167 deletions
+13 -7
View File
@@ -9,6 +9,7 @@ import (
"fmt"
"net/url"
"path/filepath"
"strconv"
"sync"
"time"
@@ -72,6 +73,8 @@ const (
}
}
`
//TODO: temporary until fix org isolation
mainOrgID = 1
)
type Alertmanager struct {
@@ -168,7 +171,7 @@ func (am *Alertmanager) Ready() bool {
func (am *Alertmanager) Run(ctx context.Context) error {
// Make sure dispatcher starts. We can tolerate future reload failures.
if err := am.SyncAndApplyConfigFromDatabase(); err != nil {
if err := am.SyncAndApplyConfigFromDatabase(mainOrgID); err != nil {
am.logger.Error("unable to sync configuration", "err", err)
}
@@ -177,7 +180,7 @@ func (am *Alertmanager) Run(ctx context.Context) error {
case <-ctx.Done():
return am.StopAndWait()
case <-time.After(pollInterval):
if err := am.SyncAndApplyConfigFromDatabase(); err != nil {
if err := am.SyncAndApplyConfigFromDatabase(mainOrgID); err != nil {
am.logger.Error("unable to sync configuration", "err", err)
}
}
@@ -203,7 +206,7 @@ func (am *Alertmanager) StopAndWait() error {
// 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(orgID int64) error {
am.reloadConfigMtx.Lock()
defer am.reloadConfigMtx.Unlock()
@@ -211,6 +214,7 @@ func (am *Alertmanager) SaveAndApplyDefaultConfig() error {
AlertmanagerConfiguration: alertmanagerDefaultConfiguration,
Default: true,
ConfigurationVersion: fmt.Sprintf("v%d", ngmodels.AlertConfigurationVersion),
OrgID: orgID,
}
cfg, err := Load([]byte(alertmanagerDefaultConfiguration))
@@ -234,7 +238,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(orgID int64, cfg *apimodels.PostableUserConfig) error {
rawConfig, err := json.Marshal(&cfg)
if err != nil {
return fmt.Errorf("failed to serialize to the Alertmanager configuration: %w", err)
@@ -246,6 +250,7 @@ func (am *Alertmanager) SaveAndApplyConfig(cfg *apimodels.PostableUserConfig) er
cmd := &ngmodels.SaveAlertmanagerConfigurationCmd{
AlertmanagerConfiguration: string(rawConfig),
ConfigurationVersion: fmt.Sprintf("v%d", ngmodels.AlertConfigurationVersion),
OrgID: orgID,
}
err = am.Store.SaveAlertmanagerConfigurationWithCallback(cmd, func() error {
@@ -264,12 +269,12 @@ func (am *Alertmanager) SaveAndApplyConfig(cfg *apimodels.PostableUserConfig) er
// SyncAndApplyConfigFromDatabase picks the latest config from database and restarts
// the components with the new config.
func (am *Alertmanager) SyncAndApplyConfigFromDatabase() error {
func (am *Alertmanager) SyncAndApplyConfigFromDatabase(orgID int64) error {
am.reloadConfigMtx.Lock()
defer am.reloadConfigMtx.Unlock()
// First, let's get the configuration we need from the database.
q := &ngmodels.GetLatestAlertmanagerConfigurationQuery{}
q := &ngmodels.GetLatestAlertmanagerConfigurationQuery{OrgID: mainOrgID}
if err := am.Store.GetLatestAlertmanagerConfiguration(q); err != nil {
// If there's no configuration in the database, let's use the default configuration.
if errors.Is(err, store.ErrNoAlertmanagerConfiguration) {
@@ -279,6 +284,7 @@ func (am *Alertmanager) SyncAndApplyConfigFromDatabase() error {
AlertmanagerConfiguration: alertmanagerDefaultConfiguration,
Default: true,
ConfigurationVersion: fmt.Sprintf("v%d", ngmodels.AlertConfigurationVersion),
OrgID: orgID,
}
if err := am.Store.SaveAlertmanagerConfiguration(savecmd); err != nil {
return err
@@ -399,7 +405,7 @@ func (am *Alertmanager) applyConfig(cfg *apimodels.PostableUserConfig, rawConfig
}
func (am *Alertmanager) WorkingDirPath() string {
return filepath.Join(am.Settings.DataPath, workingDir)
return filepath.Join(am.Settings.DataPath, workingDir, strconv.Itoa(mainOrgID))
}
// buildIntegrationsMap builds a map of name to the list of Grafana integration notifiers off of a list of receiver config.
@@ -54,7 +54,7 @@ func setupAMTest(t *testing.T) *Alertmanager {
func TestAlertmanager_ShouldUseDefaultConfigurationWhenNoConfiguration(t *testing.T) {
am := setupAMTest(t)
require.NoError(t, am.SyncAndApplyConfigFromDatabase())
require.NoError(t, am.SyncAndApplyConfigFromDatabase(mainOrgID))
require.NotNil(t, am.config)
}