grafana/pkg/services/sqlstore/migrations/external_alertmanagers.go
Marcus Efraimsson 6768c6c059
Chore: Remove public vars in setting package (#81018)
Removes the public variable setting.SecretKey plus some other ones. 
Introduces some new functions for creating setting.Cfg.
2024-01-23 12:36:22 +01:00

148 lines
3.7 KiB
Go

package migrations
import (
"fmt"
"net/url"
"os"
"time"
"xorm.io/xorm"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
func AddExternalAlertmanagerToDatasourceMigration(mg *migrator.Migrator) {
mg.AddMigration("migrate external alertmanagers to datsourcse", &externalAlertmanagerToDatasources{})
}
type externalAlertmanagerToDatasources struct {
migrator.MigrationBase
}
type AdminConfiguration struct {
OrgID int64 `xorm:"org_id"`
Alertmanagers []string
CreatedAt int64 `xorm:"created_at"`
UpdatedAt int64 `xorm:"updated_at"`
}
func (e externalAlertmanagerToDatasources) SQL(dialect migrator.Dialect) string {
return "migrate external alertmanagers to datasource"
}
func (e externalAlertmanagerToDatasources) Exec(sess *xorm.Session, mg *migrator.Migrator) error {
var results []AdminConfiguration
err := sess.SQL("SELECT org_id, alertmanagers, created_at, updated_at FROM ngalert_configuration").Find(&results)
if err != nil {
return err
}
for _, result := range results {
for _, am := range removeDuplicates(result.Alertmanagers) {
u, err := url.Parse(am)
if err != nil {
return err
}
uri := fmt.Sprintf("%s://%s%s", u.Scheme, u.Host, u.Path)
uid, err := generateNewDatasourceUid(sess, result.OrgID)
if err != nil {
return err
}
ds := &datasources.DataSource{
OrgID: result.OrgID,
Name: fmt.Sprintf("alertmanager-%s", uid),
Type: "alertmanager",
Access: "proxy",
URL: uri,
Created: time.Unix(result.CreatedAt, 0),
Updated: time.Unix(result.UpdatedAt, 0),
UID: uid,
Version: 1,
JsonData: simplejson.NewFromAny(map[string]any{
"handleGrafanaManagedAlerts": true,
"implementation": "prometheus",
}),
SecureJsonData: map[string][]byte{},
}
if u.User != nil {
ds.BasicAuth = true
ds.BasicAuthUser = u.User.Username()
if password, ok := u.User.Password(); ok {
ds.SecureJsonData = getEncryptedJsonData(mg.Cfg, map[string]string{
"basicAuthPassword": password,
}, log.New("securejsondata"))
}
}
rowsAffected, err := sess.Table("data_source").Insert(ds)
if err != nil {
return err
}
if rowsAffected == 0 {
return fmt.Errorf("expected 1 row, got %d", rowsAffected)
}
}
}
return nil
}
func removeDuplicates(strs []string) []string {
var res []string
found := map[string]bool{}
for _, str := range strs {
if found[str] {
continue
}
found[str] = true
res = append(res, str)
}
return res
}
func generateNewDatasourceUid(sess *xorm.Session, orgId int64) (string, error) {
for i := 0; i < 3; i++ {
uid := util.GenerateShortUID()
exists, err := sess.Table("data_source").Where("uid = ? AND org_id = ?", uid, orgId).Exist()
if err != nil {
return "", err
}
if !exists {
return uid, nil
}
}
return "", datasources.ErrDataSourceFailedGenerateUniqueUid
}
// SecureJsonData is used to store encrypted data (for example in data_source table). Only values are separately
// encrypted.
type secureJsonData map[string][]byte
// getEncryptedJsonData returns map where all keys are encrypted.
func getEncryptedJsonData(cfg *setting.Cfg, sjd map[string]string, log log.Logger) secureJsonData {
encrypted := make(secureJsonData)
for key, data := range sjd {
encryptedData, err := util.Encrypt([]byte(data), cfg.SecretKey)
if err != nil {
log.Error(err.Error())
os.Exit(1)
}
encrypted[key] = encryptedData
}
return encrypted
}