mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Support storing sensitive notifier settings securely/encrypted (#25114)
Support storing sensitive notification settings securely/encrypted. Move slack notifier url and api token to secure settings. Migrating slack notifier to store token and url encrypted is currently a manual process by saving an existing slack alert notification channel. saving an existing slack alert notification channel will reset the stored non-secure url and token. Closes #25113 Ref #25967 Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
This commit is contained in:
@@ -281,6 +281,11 @@ func CreateAlertNotification(c *models.ReqContext, cmd models.CreateAlertNotific
|
||||
func UpdateAlertNotification(c *models.ReqContext, cmd models.UpdateAlertNotificationCommand) Response {
|
||||
cmd.OrgId = c.OrgId
|
||||
|
||||
err := fillWithSecureSettingsData(&cmd)
|
||||
if err != nil {
|
||||
return Error(500, "Failed to update alert notification", err)
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(&cmd); err != nil {
|
||||
return Error(500, "Failed to update alert notification", err)
|
||||
}
|
||||
@@ -289,13 +294,27 @@ func UpdateAlertNotification(c *models.ReqContext, cmd models.UpdateAlertNotific
|
||||
return Error(404, "Alert notification not found", nil)
|
||||
}
|
||||
|
||||
return JSON(200, dtos.NewAlertNotification(cmd.Result))
|
||||
query := models.GetAlertNotificationsQuery{
|
||||
OrgId: c.OrgId,
|
||||
Id: cmd.Id,
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(&query); err != nil {
|
||||
return Error(500, "Failed to get alert notification", err)
|
||||
}
|
||||
|
||||
return JSON(200, dtos.NewAlertNotification(query.Result))
|
||||
}
|
||||
|
||||
func UpdateAlertNotificationByUID(c *models.ReqContext, cmd models.UpdateAlertNotificationWithUidCommand) Response {
|
||||
cmd.OrgId = c.OrgId
|
||||
cmd.Uid = c.Params("uid")
|
||||
|
||||
err := fillWithSecureSettingsDataByUID(&cmd)
|
||||
if err != nil {
|
||||
return Error(500, "Failed to update alert notification", err)
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(&cmd); err != nil {
|
||||
return Error(500, "Failed to update alert notification", err)
|
||||
}
|
||||
@@ -304,7 +323,64 @@ func UpdateAlertNotificationByUID(c *models.ReqContext, cmd models.UpdateAlertNo
|
||||
return Error(404, "Alert notification not found", nil)
|
||||
}
|
||||
|
||||
return JSON(200, dtos.NewAlertNotification(cmd.Result))
|
||||
query := models.GetAlertNotificationsWithUidQuery{
|
||||
OrgId: cmd.OrgId,
|
||||
Uid: cmd.Uid,
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(&query); err != nil {
|
||||
return Error(500, "Failed to get alert notification", err)
|
||||
}
|
||||
|
||||
return JSON(200, dtos.NewAlertNotification(query.Result))
|
||||
}
|
||||
|
||||
func fillWithSecureSettingsData(cmd *models.UpdateAlertNotificationCommand) error {
|
||||
if len(cmd.SecureSettings) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
query := &models.GetAlertNotificationsQuery{
|
||||
OrgId: cmd.OrgId,
|
||||
Id: cmd.Id,
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secureSettings := query.Result.SecureSettings.Decrypt()
|
||||
for k, v := range secureSettings {
|
||||
if _, ok := cmd.SecureSettings[k]; !ok {
|
||||
cmd.SecureSettings[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func fillWithSecureSettingsDataByUID(cmd *models.UpdateAlertNotificationWithUidCommand) error {
|
||||
if len(cmd.SecureSettings) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
query := &models.GetAlertNotificationsWithUidQuery{
|
||||
OrgId: cmd.OrgId,
|
||||
Uid: cmd.Uid,
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secureSettings := query.Result.SecureSettings.Decrypt()
|
||||
for k, v := range secureSettings {
|
||||
if _, ok := cmd.SecureSettings[k]; !ok {
|
||||
cmd.SecureSettings[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteAlertNotification(c *models.ReqContext) Response {
|
||||
@@ -336,9 +412,12 @@ func DeleteAlertNotificationByUID(c *models.ReqContext) Response {
|
||||
//POST /api/alert-notifications/test
|
||||
func NotificationTest(c *models.ReqContext, dto dtos.NotificationTestCommand) Response {
|
||||
cmd := &alerting.NotificationTestCommand{
|
||||
Name: dto.Name,
|
||||
Type: dto.Type,
|
||||
Settings: dto.Settings,
|
||||
OrgID: c.OrgId,
|
||||
ID: dto.ID,
|
||||
Name: dto.Name,
|
||||
Type: dto.Type,
|
||||
Settings: dto.Settings,
|
||||
SecureSettings: dto.SecureSettings,
|
||||
}
|
||||
|
||||
if err := bus.Dispatch(cmd); err != nil {
|
||||
|
@@ -48,7 +48,7 @@ func formatShort(interval time.Duration) string {
|
||||
}
|
||||
|
||||
func NewAlertNotification(notification *models.AlertNotification) *AlertNotification {
|
||||
return &AlertNotification{
|
||||
dto := &AlertNotification{
|
||||
Id: notification.Id,
|
||||
Uid: notification.Uid,
|
||||
Name: notification.Name,
|
||||
@@ -60,7 +60,16 @@ func NewAlertNotification(notification *models.AlertNotification) *AlertNotifica
|
||||
SendReminder: notification.SendReminder,
|
||||
DisableResolveMessage: notification.DisableResolveMessage,
|
||||
Settings: notification.Settings,
|
||||
SecureFields: map[string]bool{},
|
||||
}
|
||||
|
||||
if notification.SecureSettings != nil {
|
||||
for k := range notification.SecureSettings {
|
||||
dto.SecureFields[k] = true
|
||||
}
|
||||
}
|
||||
|
||||
return dto
|
||||
}
|
||||
|
||||
type AlertNotification struct {
|
||||
@@ -75,6 +84,7 @@ type AlertNotification struct {
|
||||
Created time.Time `json:"created"`
|
||||
Updated time.Time `json:"updated"`
|
||||
Settings *simplejson.Json `json:"settings"`
|
||||
SecureFields map[string]bool `json:"secureFields"`
|
||||
}
|
||||
|
||||
func NewAlertNotificationLookup(notification *models.AlertNotification) *AlertNotificationLookup {
|
||||
@@ -122,12 +132,14 @@ type EvalMatch struct {
|
||||
}
|
||||
|
||||
type NotificationTestCommand struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
SendReminder bool `json:"sendReminder"`
|
||||
DisableResolveMessage bool `json:"disableResolveMessage"`
|
||||
Frequency string `json:"frequency"`
|
||||
Settings *simplejson.Json `json:"settings"`
|
||||
ID int64 `json:"id,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
SendReminder bool `json:"sendReminder"`
|
||||
DisableResolveMessage bool `json:"disableResolveMessage"`
|
||||
Frequency string `json:"frequency"`
|
||||
Settings *simplejson.Json `json:"settings"`
|
||||
SecureSettings map[string]string `json:"secureSettings"`
|
||||
}
|
||||
|
||||
type PauseAlertCommand struct {
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/securejsondata"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
)
|
||||
|
||||
@@ -24,59 +25,63 @@ var (
|
||||
)
|
||||
|
||||
type AlertNotification struct {
|
||||
Id int64 `json:"id"`
|
||||
Uid string `json:"-"`
|
||||
OrgId int64 `json:"-"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
SendReminder bool `json:"sendReminder"`
|
||||
DisableResolveMessage bool `json:"disableResolveMessage"`
|
||||
Frequency time.Duration `json:"frequency"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
Settings *simplejson.Json `json:"settings"`
|
||||
Created time.Time `json:"created"`
|
||||
Updated time.Time `json:"updated"`
|
||||
Id int64 `json:"id"`
|
||||
Uid string `json:"-"`
|
||||
OrgId int64 `json:"-"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
SendReminder bool `json:"sendReminder"`
|
||||
DisableResolveMessage bool `json:"disableResolveMessage"`
|
||||
Frequency time.Duration `json:"frequency"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
Settings *simplejson.Json `json:"settings"`
|
||||
SecureSettings securejsondata.SecureJsonData `json:"secureSettings"`
|
||||
Created time.Time `json:"created"`
|
||||
Updated time.Time `json:"updated"`
|
||||
}
|
||||
|
||||
type CreateAlertNotificationCommand struct {
|
||||
Uid string `json:"uid"`
|
||||
Name string `json:"name" binding:"Required"`
|
||||
Type string `json:"type" binding:"Required"`
|
||||
SendReminder bool `json:"sendReminder"`
|
||||
DisableResolveMessage bool `json:"disableResolveMessage"`
|
||||
Frequency string `json:"frequency"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
Settings *simplejson.Json `json:"settings"`
|
||||
Uid string `json:"uid"`
|
||||
Name string `json:"name" binding:"Required"`
|
||||
Type string `json:"type" binding:"Required"`
|
||||
SendReminder bool `json:"sendReminder"`
|
||||
DisableResolveMessage bool `json:"disableResolveMessage"`
|
||||
Frequency string `json:"frequency"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
Settings *simplejson.Json `json:"settings"`
|
||||
SecureSettings map[string]string `json:"secureSettings"`
|
||||
|
||||
OrgId int64 `json:"-"`
|
||||
Result *AlertNotification
|
||||
}
|
||||
|
||||
type UpdateAlertNotificationCommand struct {
|
||||
Id int64 `json:"id" binding:"Required"`
|
||||
Uid string `json:"uid"`
|
||||
Name string `json:"name" binding:"Required"`
|
||||
Type string `json:"type" binding:"Required"`
|
||||
SendReminder bool `json:"sendReminder"`
|
||||
DisableResolveMessage bool `json:"disableResolveMessage"`
|
||||
Frequency string `json:"frequency"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
Settings *simplejson.Json `json:"settings" binding:"Required"`
|
||||
Id int64 `json:"id" binding:"Required"`
|
||||
Uid string `json:"uid"`
|
||||
Name string `json:"name" binding:"Required"`
|
||||
Type string `json:"type" binding:"Required"`
|
||||
SendReminder bool `json:"sendReminder"`
|
||||
DisableResolveMessage bool `json:"disableResolveMessage"`
|
||||
Frequency string `json:"frequency"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
Settings *simplejson.Json `json:"settings" binding:"Required"`
|
||||
SecureSettings map[string]string `json:"secureSettings"`
|
||||
|
||||
OrgId int64 `json:"-"`
|
||||
Result *AlertNotification
|
||||
}
|
||||
|
||||
type UpdateAlertNotificationWithUidCommand struct {
|
||||
Uid string `json:"-"`
|
||||
NewUid string `json:"uid"`
|
||||
Name string `json:"name" binding:"Required"`
|
||||
Type string `json:"type" binding:"Required"`
|
||||
SendReminder bool `json:"sendReminder"`
|
||||
DisableResolveMessage bool `json:"disableResolveMessage"`
|
||||
Frequency string `json:"frequency"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
Settings *simplejson.Json `json:"settings" binding:"Required"`
|
||||
Uid string `json:"-"`
|
||||
NewUid string `json:"uid"`
|
||||
Name string `json:"name" binding:"Required"`
|
||||
Type string `json:"type" binding:"Required"`
|
||||
SendReminder bool `json:"sendReminder"`
|
||||
DisableResolveMessage bool `json:"disableResolveMessage"`
|
||||
Frequency string `json:"frequency"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
Settings *simplejson.Json `json:"settings" binding:"Required"`
|
||||
SecureSettings map[string]string `json:"secureSettings"`
|
||||
|
||||
OrgId int64
|
||||
Result *AlertNotification
|
||||
@@ -157,3 +162,11 @@ type GetOrCreateNotificationStateQuery struct {
|
||||
|
||||
Result *AlertNotificationState
|
||||
}
|
||||
|
||||
// decryptedValue returns decrypted value from secureSettings
|
||||
func (an *AlertNotification) DecryptedValue(field string, fallback string) string {
|
||||
if value, ok := an.SecureSettings.DecryptedValue(field); ok {
|
||||
return value
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
@@ -31,7 +31,19 @@ func init() {
|
||||
<h3 class="page-heading">Slack settings</h3>
|
||||
<div class="gf-form max-width-30">
|
||||
<span class="gf-form-label width-8">Url</span>
|
||||
<input type="text" required class="gf-form-input max-width-30" ng-model="ctrl.model.settings.url" placeholder="Slack incoming webhook url"></input>
|
||||
<div class="gf-form gf-form--grow" ng-if="!ctrl.model.secureFields.url">
|
||||
<input type="text"
|
||||
required
|
||||
class="gf-form-input max-width-30"
|
||||
ng-init="ctrl.model.secureSettings.url = ctrl.model.settings.url || null; ctrl.model.settings.url = null;"
|
||||
ng-model="ctrl.model.secureSettings.url"
|
||||
placeholder="Slack incoming webhook url">
|
||||
</input>
|
||||
</div>
|
||||
<div class="gf-form" ng-if="ctrl.model.secureFields.url">
|
||||
<input type="text" class="gf-form-input max-width-18" disabled="disabled" value="configured" />
|
||||
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.model.secureFields.url = false">reset</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form max-width-30">
|
||||
<span class="gf-form-label width-8">Recipient</span>
|
||||
@@ -114,15 +126,22 @@ func init() {
|
||||
</info-popover>
|
||||
</div>
|
||||
<div class="gf-form max-width-30">
|
||||
<span class="gf-form-label width-8">Token</span>
|
||||
<input type="text"
|
||||
class="gf-form-input max-width-30"
|
||||
ng-model="ctrl.model.settings.token"
|
||||
data-placement="right">
|
||||
</input>
|
||||
<info-popover mode="right-absolute">
|
||||
Provide a bot token to use the Slack file.upload API (starts with "xoxb"). Specify Recipient for this to work
|
||||
</info-popover>
|
||||
<div class="gf-form gf-form--v-stretch"><label class="gf-form-label width-8">Token</label></div>
|
||||
<div class="gf-form gf-form--grow" ng-if="!ctrl.model.secureFields.token">
|
||||
<input type="text"
|
||||
class="gf-form-input max-width-30"
|
||||
ng-init="ctrl.model.secureSettings.token = ctrl.model.settings.token || null; ctrl.model.settings.token = null;"
|
||||
ng-model="ctrl.model.secureSettings.token"
|
||||
data-placement="right">
|
||||
</input>
|
||||
<info-popover mode="right-absolute">
|
||||
Provide a bot token to use the Slack file.upload API (starts with "xoxb"). Specify Recipient for this to work
|
||||
</info-popover>
|
||||
</div>
|
||||
<div class="gf-form" ng-if="ctrl.model.secureFields.token">
|
||||
<input type="text" class="gf-form-input max-width-18" disabled="disabled" value="configured" />
|
||||
<a class="btn btn-secondary gf-form-btn" href="#" ng-click="ctrl.model.secureFields.token = false">reset</a>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
Options: []alerting.NotifierOption{
|
||||
@@ -211,7 +230,7 @@ var reRecipient *regexp.Regexp = regexp.MustCompile("^((@[a-z0-9][a-zA-Z0-9._-]*
|
||||
|
||||
// NewSlackNotifier is the constructor for the Slack notifier
|
||||
func NewSlackNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
|
||||
url := model.Settings.Get("url").MustString()
|
||||
url := model.DecryptedValue("url", model.Settings.Get("url").MustString())
|
||||
if url == "" {
|
||||
return nil, alerting.ValidationError{Reason: "Could not find url property in settings"}
|
||||
}
|
||||
@@ -226,7 +245,8 @@ func NewSlackNotifier(model *models.AlertNotification) (alerting.Notifier, error
|
||||
mentionUsersStr := model.Settings.Get("mentionUsers").MustString()
|
||||
mentionGroupsStr := model.Settings.Get("mentionGroups").MustString()
|
||||
mentionChannel := model.Settings.Get("mentionChannel").MustString()
|
||||
token := model.Settings.Get("token").MustString()
|
||||
token := model.DecryptedValue("token", model.Settings.Get("token").MustString())
|
||||
|
||||
uploadImage := model.Settings.Get("uploadImage").MustBool(true)
|
||||
|
||||
if mentionChannel != "" && mentionChannel != "here" && mentionChannel != "channel" {
|
||||
|
@@ -3,6 +3,7 @@ package notifiers
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/securejsondata"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
@@ -96,6 +97,49 @@ func TestSlackNotifier(t *testing.T) {
|
||||
So(slackNotifier.Token, ShouldEqual, "xoxb-XXXXXXXX-XXXXXXXX-XXXXXXXXXX")
|
||||
})
|
||||
|
||||
Convey("from settings with Recipient, Username, IconEmoji, IconUrl, MentionUsers, MentionGroups, MentionChannel, and Secured Token", func() {
|
||||
json := `
|
||||
{
|
||||
"url": "http://google.com",
|
||||
"recipient": "#ds-opentsdb",
|
||||
"username": "Grafana Alerts",
|
||||
"icon_emoji": ":smile:",
|
||||
"icon_url": "https://grafana.com/img/fav32.png",
|
||||
"mentionUsers": "user1, user2",
|
||||
"mentionGroups": "group1, group2",
|
||||
"mentionChannel": "here",
|
||||
"token": "uenc-XXXXXXXX-XXXXXXXX-XXXXXXXXXX"
|
||||
}`
|
||||
|
||||
settingsJSON, err := simplejson.NewJson([]byte(json))
|
||||
securedSettingsJSON := securejsondata.GetEncryptedJsonData(map[string]string{
|
||||
"token": "xenc-XXXXXXXX-XXXXXXXX-XXXXXXXXXX",
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
model := &models.AlertNotification{
|
||||
Name: "ops",
|
||||
Type: "slack",
|
||||
Settings: settingsJSON,
|
||||
SecureSettings: securedSettingsJSON,
|
||||
}
|
||||
|
||||
not, err := NewSlackNotifier(model)
|
||||
slackNotifier := not.(*SlackNotifier)
|
||||
|
||||
So(err, ShouldBeNil)
|
||||
So(slackNotifier.Name, ShouldEqual, "ops")
|
||||
So(slackNotifier.Type, ShouldEqual, "slack")
|
||||
So(slackNotifier.URL, ShouldEqual, "http://google.com")
|
||||
So(slackNotifier.Recipient, ShouldEqual, "#ds-opentsdb")
|
||||
So(slackNotifier.Username, ShouldEqual, "Grafana Alerts")
|
||||
So(slackNotifier.IconEmoji, ShouldEqual, ":smile:")
|
||||
So(slackNotifier.IconURL, ShouldEqual, "https://grafana.com/img/fav32.png")
|
||||
So(slackNotifier.MentionUsers, ShouldResemble, []string{"user1", "user2"})
|
||||
So(slackNotifier.MentionGroups, ShouldResemble, []string{"group1", "group2"})
|
||||
So(slackNotifier.MentionChannel, ShouldEqual, "here")
|
||||
So(slackNotifier.Token, ShouldEqual, "xenc-XXXXXXXX-XXXXXXXX-XXXXXXXXXX")
|
||||
})
|
||||
|
||||
Convey("with channel recipient with spaces should return an error", func() {
|
||||
json := `
|
||||
{
|
||||
|
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/securejsondata"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/null"
|
||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||
@@ -14,10 +16,13 @@ import (
|
||||
// NotificationTestCommand initiates an test
|
||||
// execution of an alert notification.
|
||||
type NotificationTestCommand struct {
|
||||
State models.AlertStateType
|
||||
Name string
|
||||
Type string
|
||||
Settings *simplejson.Json
|
||||
OrgID int64
|
||||
ID int64
|
||||
State models.AlertStateType
|
||||
Name string
|
||||
Type string
|
||||
Settings *simplejson.Json
|
||||
SecureSettings map[string]string
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -37,6 +42,28 @@ func handleNotificationTestCommand(cmd *NotificationTestCommand) error {
|
||||
Settings: cmd.Settings,
|
||||
}
|
||||
|
||||
secureSettingsMap := map[string]string{}
|
||||
|
||||
if cmd.ID > 0 {
|
||||
query := &models.GetAlertNotificationsQuery{
|
||||
OrgId: cmd.OrgID,
|
||||
Id: cmd.ID,
|
||||
}
|
||||
if err := bus.Dispatch(query); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if query.Result.SecureSettings != nil {
|
||||
secureSettingsMap = query.Result.SecureSettings.Decrypt()
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range cmd.SecureSettings {
|
||||
secureSettingsMap[k] = v
|
||||
}
|
||||
|
||||
model.SecureSettings = securejsondata.GetEncryptedJsonData(secureSettingsMap)
|
||||
|
||||
notifiers, err := InitNotifier(model)
|
||||
|
||||
if err != nil {
|
||||
|
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/components/securejsondata"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
@@ -120,6 +121,7 @@ func GetAlertNotificationsWithUidToSend(query *models.GetAlertNotificationsWithU
|
||||
alert_notification.created,
|
||||
alert_notification.updated,
|
||||
alert_notification.settings,
|
||||
alert_notification.secure_settings,
|
||||
alert_notification.is_default,
|
||||
alert_notification.disable_resolve_message,
|
||||
alert_notification.send_reminder,
|
||||
@@ -192,6 +194,7 @@ func getAlertNotificationInternal(query *models.GetAlertNotificationsQuery, sess
|
||||
alert_notification.created,
|
||||
alert_notification.updated,
|
||||
alert_notification.settings,
|
||||
alert_notification.secure_settings,
|
||||
alert_notification.is_default,
|
||||
alert_notification.disable_resolve_message,
|
||||
alert_notification.send_reminder,
|
||||
@@ -241,6 +244,7 @@ func getAlertNotificationWithUidInternal(query *models.GetAlertNotificationsWith
|
||||
alert_notification.created,
|
||||
alert_notification.updated,
|
||||
alert_notification.settings,
|
||||
alert_notification.secure_settings,
|
||||
alert_notification.is_default,
|
||||
alert_notification.disable_resolve_message,
|
||||
alert_notification.send_reminder,
|
||||
@@ -308,12 +312,20 @@ func CreateAlertNotificationCommand(cmd *models.CreateAlertNotificationCommand)
|
||||
}
|
||||
}
|
||||
|
||||
// delete empty keys
|
||||
for k, v := range cmd.SecureSettings {
|
||||
if v == "" {
|
||||
delete(cmd.SecureSettings, k)
|
||||
}
|
||||
}
|
||||
|
||||
alertNotification := &models.AlertNotification{
|
||||
Uid: cmd.Uid,
|
||||
OrgId: cmd.OrgId,
|
||||
Name: cmd.Name,
|
||||
Type: cmd.Type,
|
||||
Settings: cmd.Settings,
|
||||
SecureSettings: securejsondata.GetEncryptedJsonData(cmd.SecureSettings),
|
||||
SendReminder: cmd.SendReminder,
|
||||
DisableResolveMessage: cmd.DisableResolveMessage,
|
||||
Frequency: frequency,
|
||||
@@ -365,8 +377,16 @@ func UpdateAlertNotification(cmd *models.UpdateAlertNotificationCommand) error {
|
||||
return fmt.Errorf("Alert notification name %s already exists", cmd.Name)
|
||||
}
|
||||
|
||||
// delete empty keys
|
||||
for k, v := range cmd.SecureSettings {
|
||||
if v == "" {
|
||||
delete(cmd.SecureSettings, k)
|
||||
}
|
||||
}
|
||||
|
||||
current.Updated = time.Now()
|
||||
current.Settings = cmd.Settings
|
||||
current.SecureSettings = securejsondata.GetEncryptedJsonData(cmd.SecureSettings)
|
||||
current.Name = cmd.Name
|
||||
current.Type = cmd.Type
|
||||
current.IsDefault = cmd.IsDefault
|
||||
@@ -430,6 +450,7 @@ func UpdateAlertNotificationWithUid(cmd *models.UpdateAlertNotificationWithUidCo
|
||||
Frequency: cmd.Frequency,
|
||||
IsDefault: cmd.IsDefault,
|
||||
Settings: cmd.Settings,
|
||||
SecureSettings: cmd.SecureSettings,
|
||||
|
||||
OrgId: cmd.OrgId,
|
||||
}
|
||||
|
@@ -167,4 +167,8 @@ func addAlertMigrations(mg *Migrator) {
|
||||
mg.AddMigration("Remove unique index org_id_name", NewDropIndexMigration(alert_notification, &Index{
|
||||
Cols: []string{"org_id", "name"}, Type: UniqueIndex,
|
||||
}))
|
||||
|
||||
mg.AddMigration("Add column secure_settings in alert_notification", NewAddColumnMigration(alert_notification, &Column{
|
||||
Name: "secure_settings", Type: DB_Text, Nullable: true,
|
||||
}))
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ export class AlertNotificationEditCtrl {
|
||||
severity: 'critical',
|
||||
uploadImage: true,
|
||||
},
|
||||
secureSettings: {},
|
||||
isDefault: false,
|
||||
};
|
||||
getFrequencySuggestion: any;
|
||||
@@ -72,6 +73,7 @@ export class AlertNotificationEditCtrl {
|
||||
this.navModel.breadcrumbs.push({ text: result.name });
|
||||
this.navModel.node = { text: result.name };
|
||||
result.settings = _.defaults(result.settings, this.defaults.settings);
|
||||
result.secureSettings = _.defaults(result.secureSettings, this.defaults.secureSettings);
|
||||
return result;
|
||||
});
|
||||
})
|
||||
@@ -149,6 +151,7 @@ export class AlertNotificationEditCtrl {
|
||||
|
||||
typeChanged() {
|
||||
this.model.settings = _.defaults({}, this.defaults.settings);
|
||||
this.model.secureSettings = _.defaults({}, this.defaults.secureSettings);
|
||||
this.notifierTemplateId = this.getNotifierTemplateId(this.model.type);
|
||||
}
|
||||
|
||||
@@ -157,13 +160,18 @@ export class AlertNotificationEditCtrl {
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
const payload: any = {
|
||||
name: this.model.name,
|
||||
type: this.model.type,
|
||||
frequency: this.model.frequency,
|
||||
settings: this.model.settings,
|
||||
secureSettings: this.model.secureSettings,
|
||||
};
|
||||
|
||||
if (this.model.id) {
|
||||
payload.id = this.model.id;
|
||||
}
|
||||
|
||||
promiseToDigest(this.$scope)(getBackendSrv().post(`/api/alert-notifications/test`, payload));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user