From cc74b1fe46164bd2bf73aa89089387be11675aff Mon Sep 17 00:00:00 2001 From: gotjosh Date: Thu, 18 Mar 2021 18:12:28 +0000 Subject: [PATCH] Alerting: Add database table for persisting alerting configuration (#32042) * Alerting: Add database table for persisting alerting configuration * Fix the linter * Address review comments * Don't split templates and configuration It is already bundled together as part of a of the API so might as well marshall it directly. --- pkg/services/ngalert/database_mig.go | 15 +++++++++ pkg/services/ngalert/models/alertmanager.go | 20 ++++++++++++ pkg/services/ngalert/ngalert.go | 1 + pkg/services/ngalert/store/alertmanager.go | 34 +++++++++++++++++++++ pkg/services/ngalert/store/database.go | 3 ++ 5 files changed, 73 insertions(+) create mode 100644 pkg/services/ngalert/models/alertmanager.go create mode 100644 pkg/services/ngalert/store/alertmanager.go diff --git a/pkg/services/ngalert/database_mig.go b/pkg/services/ngalert/database_mig.go index ec130328244..41054c82432 100644 --- a/pkg/services/ngalert/database_mig.go +++ b/pkg/services/ngalert/database_mig.go @@ -107,3 +107,18 @@ func alertInstanceMigration(mg *migrator.Migrator) { mg.AddMigration("add index in alert_instance table on def_org_id, def_uid and current_state columns", migrator.NewAddIndexMigration(alertInstance, alertInstance.Indices[0])) mg.AddMigration("add index in alert_instance table on def_org_id, current_state columns", migrator.NewAddIndexMigration(alertInstance, alertInstance.Indices[1])) } + +func alertmanagerConfigurationMigration(mg *migrator.Migrator) { + alertConfiguration := migrator.Table{ + Name: "alert_configuration", + Columns: []*migrator.Column{ + {Name: "id", Type: migrator.DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, + {Name: "alertmanager_configuration", Type: migrator.DB_Text, Nullable: false}, + {Name: "configuration_version", Type: migrator.DB_NVarchar, Length: 3}, // In a format of vXX e.g. v1, v2, v10, etc + {Name: "created_at", Type: migrator.DB_Int, Nullable: false}, + {Name: "updated_at", Type: migrator.DB_Int, Nullable: false}, + }, + } + + mg.AddMigration("create_alert_configuration_table", migrator.NewAddTableMigration(alertConfiguration)) +} diff --git a/pkg/services/ngalert/models/alertmanager.go b/pkg/services/ngalert/models/alertmanager.go new file mode 100644 index 00000000000..3860ec99f35 --- /dev/null +++ b/pkg/services/ngalert/models/alertmanager.go @@ -0,0 +1,20 @@ +package models + +import "time" + +// AlertConfiguration represents a single version of the Alerting Engine Configuration. +type AlertConfiguration struct { + ID int64 `xorm:"pk autoincr 'id'"` + + AlertmanagerConfiguration string + ConfigurationVersion string + CreatedAt time.Time `xorm:"created"` + UpdatedAt time.Time `xorm:"updated"` +} + +// GetLatestAlertmanagerConfigurationQuery is the query to get the latest alertmanager configuration. +type GetLatestAlertmanagerConfigurationQuery struct { + ID int64 + + Result *AlertConfiguration +} diff --git a/pkg/services/ngalert/ngalert.go b/pkg/services/ngalert/ngalert.go index 2aae9542c57..0a25656a462 100644 --- a/pkg/services/ngalert/ngalert.go +++ b/pkg/services/ngalert/ngalert.go @@ -104,4 +104,5 @@ func (ng *AlertNG) AddMigration(mg *migrator.Migrator) { addAlertDefinitionVersionMigrations(mg) // Create alert_instance table alertInstanceMigration(mg) + alertmanagerConfigurationMigration(mg) } diff --git a/pkg/services/ngalert/store/alertmanager.go b/pkg/services/ngalert/store/alertmanager.go new file mode 100644 index 00000000000..16b64c2661a --- /dev/null +++ b/pkg/services/ngalert/store/alertmanager.go @@ -0,0 +1,34 @@ +package store + +import ( + "context" + "fmt" + + "github.com/grafana/grafana/pkg/services/ngalert/models" + "github.com/grafana/grafana/pkg/services/sqlstore" +) + +var ( + // ErrNoAlertmanagerConfiguration is an error for when no alertmanager configuration is found. + ErrNoAlertmanagerConfiguration = fmt.Errorf("could not find an alert configuration") +) + +// 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 { + 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").Limit(1).Get(c) + if err != nil { + return err + } + + if !ok { + return ErrNoAlertmanagerConfiguration + } + + query.Result = c + return nil + }) +} diff --git a/pkg/services/ngalert/store/database.go b/pkg/services/ngalert/store/database.go index a5783acdb7e..067fe1c848e 100644 --- a/pkg/services/ngalert/store/database.go +++ b/pkg/services/ngalert/store/database.go @@ -35,6 +35,9 @@ type Store interface { SaveAlertInstance(cmd *models.SaveAlertInstanceCommand) error ValidateAlertDefinition(*models.AlertDefinition, bool) error UpdateAlertDefinitionPaused(*models.UpdateAlertDefinitionPausedCommand) error + + // Alertmanager + GetLatestAlertmanagerConfiguration(cmd *models.GetLatestAlertmanagerConfigurationQuery) error } // DBstore stores the alert definitions and instances in the database.