mirror of https://github.com/grafana/grafana
[Alerting]: Alertmanager API implementation (#32174)
* Add validation for grafana recipient * Alertmanager API implementation (WIP) * Fix encoding/decoding receiver settings from/to YAML * Save templates together with the configuration * update POST to apply latest config * Alertmanager service enabled by the ngalert toggle * Silence API integration with Alertmanager * Apply suggestions from code review Co-authored-by: gotjosh <josue@grafana.com> Co-authored-by: Ganesh Vernekar <15064823+codesome@users.noreply.github.com>pull/32449/head^2
parent
b0ffcfd558
commit
a5e95823b2
@ -0,0 +1,359 @@ |
||||
package api |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
"net/http" |
||||
"time" |
||||
|
||||
"gopkg.in/yaml.v3" |
||||
|
||||
"github.com/go-openapi/strfmt" |
||||
apimodels "github.com/grafana/alerting-api/pkg/api" |
||||
"github.com/grafana/grafana/pkg/api/response" |
||||
"github.com/grafana/grafana/pkg/infra/log" |
||||
"github.com/grafana/grafana/pkg/models" |
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models" |
||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier" |
||||
"github.com/grafana/grafana/pkg/services/ngalert/store" |
||||
"github.com/grafana/grafana/pkg/util" |
||||
amv2 "github.com/prometheus/alertmanager/api/v2/models" |
||||
) |
||||
|
||||
type AlertmanagerSrv struct { |
||||
am Alertmanager |
||||
store store.AlertingStore |
||||
log log.Logger |
||||
} |
||||
|
||||
func (srv AlertmanagerSrv) RouteCreateSilence(c *models.ReqContext, postableSilence apimodels.PostableSilence) response.Response { |
||||
silenceID, err := srv.am.CreateSilence(&postableSilence) |
||||
if err != nil { |
||||
if errors.Is(err, notifier.ErrSilenceNotFound) { |
||||
return response.Error(http.StatusNotFound, err.Error(), nil) |
||||
} |
||||
|
||||
if errors.Is(err, notifier.ErrCreateSilenceBadPayload) { |
||||
return response.Error(http.StatusBadRequest, err.Error(), nil) |
||||
} |
||||
|
||||
return response.Error(http.StatusInternalServerError, "failed to create silence", err) |
||||
} |
||||
return response.JSON(http.StatusAccepted, util.DynMap{"message": "silence created", "id": silenceID}) |
||||
} |
||||
|
||||
func (srv AlertmanagerSrv) RouteDeleteAlertingConfig(c *models.ReqContext) response.Response { |
||||
// not implemented
|
||||
return response.Error(http.StatusNotImplemented, "", nil) |
||||
} |
||||
|
||||
func (srv AlertmanagerSrv) RouteDeleteSilence(c *models.ReqContext) response.Response { |
||||
silenceID := c.Params(":SilenceId") |
||||
if err := srv.am.DeleteSilence(silenceID); err != nil { |
||||
if errors.Is(err, notifier.ErrSilenceNotFound) { |
||||
return response.Error(http.StatusNotFound, err.Error(), nil) |
||||
} |
||||
return response.Error(http.StatusInternalServerError, err.Error(), nil) |
||||
} |
||||
return response.JSON(http.StatusOK, util.DynMap{"message": "silence deleted"}) |
||||
} |
||||
|
||||
func (srv AlertmanagerSrv) RouteGetAlertingConfig(c *models.ReqContext) response.Response { |
||||
query := ngmodels.GetLatestAlertmanagerConfigurationQuery{} |
||||
err := srv.store.GetLatestAlertmanagerConfiguration(&query) |
||||
if err != nil { |
||||
return response.Error(http.StatusInternalServerError, "failed to get latest configuration", err) |
||||
} |
||||
|
||||
cfg := apimodels.PostableUserConfig{} |
||||
err = yaml.Unmarshal([]byte(query.Result.AlertmanagerConfiguration), &cfg) |
||||
if err != nil { |
||||
return response.Error(http.StatusInternalServerError, "failed to unmarshal alertmanager configuration", err) |
||||
} |
||||
|
||||
var apiReceiverName string |
||||
var receivers []*apimodels.GettableGrafanaReceiver |
||||
alertmanagerCfg := cfg.AlertmanagerConfig |
||||
if len(alertmanagerCfg.Receivers) > 0 { |
||||
apiReceiverName = alertmanagerCfg.Receivers[0].Name |
||||
receivers = make([]*apimodels.GettableGrafanaReceiver, 0, len(alertmanagerCfg.Receivers[0].PostableGrafanaReceivers.GrafanaManagedReceivers)) |
||||
for _, pr := range alertmanagerCfg.Receivers[0].PostableGrafanaReceivers.GrafanaManagedReceivers { |
||||
secureFields := make(map[string]bool, len(pr.SecureSettings)) |
||||
for k := range pr.SecureSettings { |
||||
secureFields[k] = true |
||||
} |
||||
gr := apimodels.GettableGrafanaReceiver{ |
||||
Uid: pr.Uid, |
||||
Name: pr.Name, |
||||
Type: pr.Type, |
||||
IsDefault: pr.IsDefault, |
||||
SendReminder: pr.SendReminder, |
||||
DisableResolveMessage: pr.DisableResolveMessage, |
||||
Frequency: pr.Frequency, |
||||
Settings: pr.Settings, |
||||
SecureFields: secureFields, |
||||
} |
||||
receivers = append(receivers, &gr) |
||||
} |
||||
} |
||||
|
||||
gettableApiReceiver := apimodels.GettableApiReceiver{ |
||||
GettableGrafanaReceivers: apimodels.GettableGrafanaReceivers{ |
||||
GrafanaManagedReceivers: receivers, |
||||
}, |
||||
} |
||||
gettableApiReceiver.Name = apiReceiverName |
||||
result := apimodels.GettableUserConfig{ |
||||
TemplateFiles: cfg.TemplateFiles, |
||||
AlertmanagerConfig: apimodels.GettableApiAlertingConfig{ |
||||
Config: alertmanagerCfg.Config, |
||||
Receivers: []*apimodels.GettableApiReceiver{ |
||||
&gettableApiReceiver, |
||||
}, |
||||
}, |
||||
} |
||||
|
||||
return response.JSON(http.StatusOK, result) |
||||
} |
||||
|
||||
func (srv AlertmanagerSrv) RouteGetAMAlertGroups(c *models.ReqContext) response.Response { |
||||
recipient := c.Params(":Recipient") |
||||
srv.log.Info("RouteGetAMAlertGroups: ", "Recipient", recipient) |
||||
now := time.Now() |
||||
result := apimodels.AlertGroups{ |
||||
&amv2.AlertGroup{ |
||||
Alerts: []*amv2.GettableAlert{ |
||||
{ |
||||
Annotations: amv2.LabelSet{ |
||||
"annotation1-1": "value1", |
||||
"annotation1-2": "value2", |
||||
}, |
||||
EndsAt: timePtr(strfmt.DateTime(now.Add(time.Hour))), |
||||
Fingerprint: stringPtr("fingerprint 1"), |
||||
Receivers: []*amv2.Receiver{ |
||||
{ |
||||
Name: stringPtr("receiver identifier 1-1"), |
||||
}, |
||||
{ |
||||
Name: stringPtr("receiver identifier 1-2"), |
||||
}, |
||||
}, |
||||
StartsAt: timePtr(strfmt.DateTime(now)), |
||||
Status: &amv2.AlertStatus{ |
||||
InhibitedBy: []string{"inhibitedBy 1"}, |
||||
SilencedBy: []string{"silencedBy 1"}, |
||||
State: stringPtr(amv2.AlertStatusStateActive), |
||||
}, |
||||
UpdatedAt: timePtr(strfmt.DateTime(now.Add(-time.Hour))), |
||||
Alert: amv2.Alert{ |
||||
GeneratorURL: strfmt.URI("a URL"), |
||||
Labels: amv2.LabelSet{ |
||||
"label1-1": "value1", |
||||
"label1-2": "value2", |
||||
}, |
||||
}, |
||||
}, |
||||
{ |
||||
Annotations: amv2.LabelSet{ |
||||
"annotation2-1": "value1", |
||||
"annotation2-2": "value2", |
||||
}, |
||||
EndsAt: timePtr(strfmt.DateTime(now.Add(time.Hour))), |
||||
Fingerprint: stringPtr("fingerprint 2"), |
||||
Receivers: []*amv2.Receiver{ |
||||
{ |
||||
Name: stringPtr("receiver identifier 2-1"), |
||||
}, |
||||
{ |
||||
Name: stringPtr("receiver identifier 2-2"), |
||||
}, |
||||
}, |
||||
StartsAt: timePtr(strfmt.DateTime(now)), |
||||
Status: &amv2.AlertStatus{ |
||||
InhibitedBy: []string{"inhibitedBy 2"}, |
||||
SilencedBy: []string{"silencedBy 2"}, |
||||
State: stringPtr(amv2.AlertStatusStateActive), |
||||
}, |
||||
UpdatedAt: timePtr(strfmt.DateTime(now.Add(-time.Hour))), |
||||
Alert: amv2.Alert{ |
||||
GeneratorURL: strfmt.URI("a URL"), |
||||
Labels: amv2.LabelSet{ |
||||
"label2-1": "value1", |
||||
"label2-2": "value2", |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
Labels: amv2.LabelSet{ |
||||
"label1-1": "value1", |
||||
"label1-2": "value2", |
||||
}, |
||||
Receiver: &amv2.Receiver{ |
||||
Name: stringPtr("receiver identifier 2-1"), |
||||
}, |
||||
}, |
||||
&amv2.AlertGroup{ |
||||
Alerts: []*amv2.GettableAlert{ |
||||
{ |
||||
Annotations: amv2.LabelSet{ |
||||
"annotation2-1": "value1", |
||||
"annotation2-2": "value2", |
||||
}, |
||||
EndsAt: timePtr(strfmt.DateTime(now.Add(time.Hour))), |
||||
Fingerprint: stringPtr("fingerprint 2"), |
||||
Receivers: []*amv2.Receiver{ |
||||
{ |
||||
Name: stringPtr("receiver identifier 2-1"), |
||||
}, |
||||
{ |
||||
Name: stringPtr("receiver identifier 2-2"), |
||||
}, |
||||
}, |
||||
StartsAt: timePtr(strfmt.DateTime(now)), |
||||
Status: &amv2.AlertStatus{ |
||||
InhibitedBy: []string{"inhibitedBy 2"}, |
||||
SilencedBy: []string{"silencedBy 2"}, |
||||
State: stringPtr(amv2.AlertStatusStateActive), |
||||
}, |
||||
UpdatedAt: timePtr(strfmt.DateTime(now.Add(-time.Hour))), |
||||
Alert: amv2.Alert{ |
||||
GeneratorURL: strfmt.URI("a URL"), |
||||
Labels: amv2.LabelSet{ |
||||
"label2-1": "value1", |
||||
"label2-2": "value2", |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
Labels: amv2.LabelSet{ |
||||
"label2-1": "value1", |
||||
"label2-2": "value2", |
||||
}, |
||||
Receiver: &amv2.Receiver{ |
||||
Name: stringPtr("receiver identifier 2-1"), |
||||
}, |
||||
}, |
||||
} |
||||
return response.JSON(http.StatusOK, result) |
||||
} |
||||
|
||||
func (srv AlertmanagerSrv) RouteGetAMAlerts(c *models.ReqContext) response.Response { |
||||
recipient := c.Params(":Recipient") |
||||
srv.log.Info("RouteGetAMAlerts: ", "Recipient", recipient) |
||||
now := time.Now() |
||||
result := apimodels.GettableAlerts{ |
||||
&amv2.GettableAlert{ |
||||
Annotations: amv2.LabelSet{ |
||||
"annotation1-1": "value1", |
||||
"annotation1-2": "value2", |
||||
}, |
||||
EndsAt: timePtr(strfmt.DateTime(now.Add(time.Hour))), |
||||
Fingerprint: stringPtr("fingerprint 1"), |
||||
Receivers: []*amv2.Receiver{ |
||||
{ |
||||
Name: stringPtr("receiver identifier 1-1"), |
||||
}, |
||||
{ |
||||
Name: stringPtr("receiver identifier 1-2"), |
||||
}, |
||||
}, |
||||
StartsAt: timePtr(strfmt.DateTime(now)), |
||||
Status: &amv2.AlertStatus{ |
||||
InhibitedBy: []string{"inhibitedBy 1"}, |
||||
SilencedBy: []string{"silencedBy 1"}, |
||||
State: stringPtr(amv2.AlertStatusStateActive), |
||||
}, |
||||
UpdatedAt: timePtr(strfmt.DateTime(now.Add(-time.Hour))), |
||||
Alert: amv2.Alert{ |
||||
GeneratorURL: strfmt.URI("a URL"), |
||||
Labels: amv2.LabelSet{ |
||||
"label1-1": "value1", |
||||
"label1-2": "value2", |
||||
}, |
||||
}, |
||||
}, |
||||
&amv2.GettableAlert{ |
||||
Annotations: amv2.LabelSet{ |
||||
"annotation2-1": "value1", |
||||
"annotation2-2": "value2", |
||||
}, |
||||
EndsAt: timePtr(strfmt.DateTime(now.Add(time.Hour))), |
||||
Fingerprint: stringPtr("fingerprint 2"), |
||||
Receivers: []*amv2.Receiver{ |
||||
{ |
||||
Name: stringPtr("receiver identifier 2-1"), |
||||
}, |
||||
{ |
||||
Name: stringPtr("receiver identifier 2-2"), |
||||
}, |
||||
}, |
||||
StartsAt: timePtr(strfmt.DateTime(now)), |
||||
Status: &amv2.AlertStatus{ |
||||
InhibitedBy: []string{"inhibitedBy 2"}, |
||||
SilencedBy: []string{"silencedBy 2"}, |
||||
State: stringPtr(amv2.AlertStatusStateActive), |
||||
}, |
||||
UpdatedAt: timePtr(strfmt.DateTime(now.Add(-time.Hour))), |
||||
Alert: amv2.Alert{ |
||||
GeneratorURL: strfmt.URI("a URL"), |
||||
Labels: amv2.LabelSet{ |
||||
"label2-1": "value1", |
||||
"label2-2": "value2", |
||||
}, |
||||
}, |
||||
}, |
||||
} |
||||
return response.JSON(http.StatusOK, result) |
||||
} |
||||
|
||||
func (srv AlertmanagerSrv) RouteGetSilence(c *models.ReqContext) response.Response { |
||||
silenceID := c.Params(":SilenceId") |
||||
gettableSilence, err := srv.am.GetSilence(silenceID) |
||||
if err != nil { |
||||
if errors.Is(err, notifier.ErrSilenceNotFound) { |
||||
return response.Error(http.StatusNotFound, err.Error(), nil) |
||||
} |
||||
// any other error here should be an unexpected failure and thus an internal error
|
||||
return response.Error(http.StatusInternalServerError, err.Error(), nil) |
||||
} |
||||
return response.JSON(http.StatusOK, gettableSilence) |
||||
} |
||||
|
||||
func (srv AlertmanagerSrv) RouteGetSilences(c *models.ReqContext) response.Response { |
||||
filters := c.QueryStrings("Filter") |
||||
gettableSilences, err := srv.am.ListSilences(filters) |
||||
if err != nil { |
||||
if errors.Is(err, notifier.ErrListSilencesBadPayload) { |
||||
return response.Error(http.StatusBadRequest, err.Error(), nil) |
||||
} |
||||
// any other error here should be an unexpected failure and thus an internal error
|
||||
return response.Error(http.StatusInternalServerError, err.Error(), nil) |
||||
} |
||||
return response.JSON(http.StatusOK, gettableSilences) |
||||
} |
||||
|
||||
func (srv AlertmanagerSrv) RoutePostAlertingConfig(c *models.ReqContext, body apimodels.PostableUserConfig) response.Response { |
||||
config, err := yaml.Marshal(&body) |
||||
if err != nil { |
||||
return response.Error(http.StatusInternalServerError, "failed to serialize to the Alertmanager configuration", err) |
||||
} |
||||
|
||||
cmd := ngmodels.SaveAlertmanagerConfigurationCmd{ |
||||
AlertmanagerConfiguration: string(config), |
||||
ConfigurationVersion: fmt.Sprintf("v%d", ngmodels.AlertConfigurationVersion), |
||||
} |
||||
if err := srv.store.SaveAlertmanagerConfiguration(&cmd); err != nil { |
||||
return response.Error(http.StatusInternalServerError, "failed to save Alertmanager configuration", err) |
||||
} |
||||
|
||||
if err := srv.am.ApplyConfig(&body); err != nil { |
||||
return response.Error(http.StatusInternalServerError, "failed to apply Alertmanager configuration", err) |
||||
} |
||||
|
||||
return response.JSON(http.StatusAccepted, util.DynMap{"message": "configuration created"}) |
||||
} |
||||
|
||||
func (srv AlertmanagerSrv) RoutePostAMAlerts(c *models.ReqContext, body apimodels.PostableAlerts) response.Response { |
||||
// not implemented
|
||||
return response.Error(http.StatusNotImplemented, "", nil) |
||||
} |
||||
@ -1,891 +0,0 @@ |
||||
/*Package api contains mock API implementation of unified alerting |
||||
* |
||||
* Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
|
||||
* |
||||
* Need to remove unused imports. |
||||
*/ |
||||
package api |
||||
|
||||
import ( |
||||
"net/http" |
||||
"time" |
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos" |
||||
|
||||
"github.com/grafana/grafana/pkg/components/securejsondata" |
||||
"github.com/grafana/grafana/pkg/components/simplejson" |
||||
|
||||
"github.com/go-openapi/strfmt" |
||||
apimodels "github.com/grafana/alerting-api/pkg/api" |
||||
"github.com/grafana/grafana/pkg/api/response" |
||||
"github.com/grafana/grafana/pkg/infra/log" |
||||
"github.com/grafana/grafana/pkg/models" |
||||
"github.com/grafana/grafana/pkg/util" |
||||
amv2 "github.com/prometheus/alertmanager/api/v2/models" |
||||
"github.com/prometheus/alertmanager/config" |
||||
) |
||||
|
||||
func toSimpleJSON(blob string) *simplejson.Json { |
||||
json, _ := simplejson.NewJson([]byte(blob)) |
||||
return json |
||||
} |
||||
|
||||
var alertmanagerReceiver = models.AlertNotification{ |
||||
Id: 1, |
||||
Uid: "alertmanager UID", |
||||
OrgId: 1, |
||||
Name: "an alert manager receiver", |
||||
Type: "prometheus-alertmanager", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"autoResolve": true, |
||||
"basicAuthUser": "user", |
||||
"httpMethod": "POST", |
||||
"severity": "critical", |
||||
"uploadImage": false, |
||||
"url": "http://localhost:9093" |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{ |
||||
"basicAuthPassword": "<basicAuthPassword>", |
||||
}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var alertmanagerReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&alertmanagerReceiver)) |
||||
|
||||
var dingdingReceiver = models.AlertNotification{ |
||||
Id: 2, |
||||
Uid: "dingding UID", |
||||
OrgId: 1, |
||||
Name: "a dingding receiver", |
||||
Type: "dingding", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"autoResolve": true, |
||||
"httpMethod": "POST", |
||||
"msgType": "link", |
||||
"severity": "critical", |
||||
"uploadImage": false, |
||||
"url": "https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxx" |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var dingdingReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&dingdingReceiver)) |
||||
|
||||
var discordReceiver = models.AlertNotification{ |
||||
Id: 3, |
||||
Uid: "discord UID", |
||||
OrgId: 1, |
||||
Name: "a discord receiver", |
||||
Type: "discord", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"autoResolve": true, |
||||
"content": "@user", |
||||
"httpMethod": "POST", |
||||
"severity": "critical", |
||||
"uploadImage": false, |
||||
"url": "http://" |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var discordReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&discordReceiver)) |
||||
|
||||
var emailReceiver = models.AlertNotification{ |
||||
Id: 4, |
||||
Uid: "email UID", |
||||
OrgId: 1, |
||||
Name: "an email receiver", |
||||
Type: "email", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"addresses": "<email>", |
||||
"autoResolve": true, |
||||
"httpMethod": "POST", |
||||
"severity": "critical", |
||||
"singleEmail": true, |
||||
"uploadImage": false |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var emailReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&emailReceiver)) |
||||
|
||||
var googlechatReceiver = models.AlertNotification{ |
||||
Id: 5, |
||||
Uid: "googlechatReceiver UID", |
||||
OrgId: 1, |
||||
Name: "a googlechat receiver", |
||||
Type: "googlechat", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"autoResolve": true, |
||||
"httpMethod": "POST", |
||||
"severity": "critical", |
||||
"uploadImage": false, |
||||
"url": "http://" |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var googlechatReceiverDTOs = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&googlechatReceiver)) |
||||
|
||||
var hipchatReceiver = models.AlertNotification{ |
||||
Id: 6, |
||||
Uid: "hipchat UID", |
||||
OrgId: 1, |
||||
Name: "a hipchat receiver", |
||||
Type: "hipchat", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"apiKey": "<apikey>", |
||||
"autoResolve": true, |
||||
"httpMethod": "POST", |
||||
"roomid": "12345", |
||||
"severity": "critical", |
||||
"uploadImage": false, |
||||
"url": "http://" |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var hipchatReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&hipchatReceiver)) |
||||
|
||||
var kafkaReceiver = models.AlertNotification{ |
||||
Id: 7, |
||||
Uid: "kafka UID", |
||||
OrgId: 1, |
||||
Name: "a kafka receiver", |
||||
Type: "kafka", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"autoResolve": true, |
||||
"httpMethod": "POST", |
||||
"kafkaRestProxy": "http://localhost:8082", |
||||
"kafkaTopic": "topic1", |
||||
"severity": "critical", |
||||
"uploadImage": false |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var kafkaReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&kafkaReceiver)) |
||||
|
||||
var lineReceiver = models.AlertNotification{ |
||||
Id: 8, |
||||
Uid: "line UID", |
||||
OrgId: 1, |
||||
Name: "a line receiver", |
||||
Type: "line", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(` "settings": { |
||||
"autoResolve": true, |
||||
"httpMethod": "POST", |
||||
"severity": "critical", |
||||
"uploadImage": false |
||||
},`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{ |
||||
"token": "<token>", |
||||
}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var lineReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&lineReceiver)) |
||||
|
||||
var opsgenieReceiver = models.AlertNotification{ |
||||
Id: 9, |
||||
Uid: "opsgenie UID", |
||||
OrgId: 1, |
||||
Name: "a opsgenie receiver", |
||||
Type: "opsgenie", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(` "settings": { |
||||
"apiUrl": "https://api.opsgenie.com/v2/alerts", |
||||
"autoClose": true, |
||||
"autoResolve": true, |
||||
"httpMethod": "POST", |
||||
"overridePriority": true, |
||||
"severity": "critical", |
||||
"uploadImage": false |
||||
},`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{ |
||||
"apiKey": "<apiKey>", |
||||
}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var opsgenieReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&opsgenieReceiver)) |
||||
|
||||
var pagerdutyReceiver = models.AlertNotification{ |
||||
Id: 10, |
||||
Uid: "pagerduty UID", |
||||
OrgId: 1, |
||||
Name: "a pagerduty receiver", |
||||
Type: "pagerduty", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"autoResolve": true, |
||||
"httpMethod": "POST", |
||||
"severity": "critical", |
||||
"uploadImage": true |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{ |
||||
"integrationKey": "<integrationKey>", |
||||
}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var pagerdutyReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&pagerdutyReceiver)) |
||||
|
||||
var pushoverReceiver = models.AlertNotification{ |
||||
Id: 11, |
||||
Uid: "pushover UID", |
||||
OrgId: 1, |
||||
Name: "a pushover receiver", |
||||
Type: "pushover", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"apiToken": "", |
||||
"autoResolve": true, |
||||
"device": "", |
||||
"expire": "", |
||||
"httpMethod": "POST", |
||||
"okPriority": "0", |
||||
"okSound": "cosmic", |
||||
"priority": "1", |
||||
"retry": "30", |
||||
"severity": "critical", |
||||
"sound": "pushover", |
||||
"uploadImage": true, |
||||
"userKey": "" |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{ |
||||
"apiToken": "<apiToken>", |
||||
"userKey": "<userKey>", |
||||
}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var pushoverReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&pushoverReceiver)) |
||||
|
||||
var sensuReceiver = models.AlertNotification{ |
||||
Id: 12, |
||||
Uid: "sensu UID", |
||||
OrgId: 1, |
||||
Name: "a sensu receiver", |
||||
Type: "sensu", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"autoResolve": true, |
||||
"handler": "", |
||||
"httpMethod": "POST", |
||||
"severity": "critical", |
||||
"source": "", |
||||
"uploadImage": false, |
||||
"url": "http://sensu-api.local:4567/results", |
||||
"username": "" |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var sensuReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&sensuReceiver)) |
||||
|
||||
var sensugoReceiver = models.AlertNotification{ |
||||
Id: 13, |
||||
Uid: "sensugo UID", |
||||
OrgId: 1, |
||||
Name: "a sensugo receiver", |
||||
Type: "sensugo", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"autoResolve": true, |
||||
"check": "", |
||||
"entity": "", |
||||
"handler": "", |
||||
"httpMethod": "POST", |
||||
"namespace": "", |
||||
"severity": "critical", |
||||
"uploadImage": false, |
||||
"url": "http://sensu-api.local:8080" |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{ |
||||
"apikey": "<apikey>", |
||||
}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var sensugoReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&sensugoReceiver)) |
||||
|
||||
var slackReceiver = models.AlertNotification{ |
||||
Id: 14, |
||||
Uid: "slack UID", |
||||
OrgId: 1, |
||||
Name: "a slack receiver", |
||||
Type: "slack", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"autoResolve": true, |
||||
"httpMethod": "POST", |
||||
"iconEmoji": "", |
||||
"iconUrl": "", |
||||
"mentionGroups": "", |
||||
"mentionUsers": "", |
||||
"recipient": "", |
||||
"severity": "critical", |
||||
"uploadImage": false, |
||||
"username": "" |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{ |
||||
"token": "<token>", |
||||
"url": "<url>", |
||||
}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var slackReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&slackReceiver)) |
||||
|
||||
var teamsReceiver = models.AlertNotification{ |
||||
Id: 15, |
||||
Uid: "teams UID", |
||||
OrgId: 1, |
||||
Name: "a teams receiver", |
||||
Type: "teams", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"autoResolve": true, |
||||
"httpMethod": "POST", |
||||
"severity": "critical", |
||||
"uploadImage": false, |
||||
"url": "http://" |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var teamsReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&teamsReceiver)) |
||||
|
||||
var telegramReceiver = models.AlertNotification{ |
||||
Id: 16, |
||||
Uid: "telegram UID", |
||||
OrgId: 1, |
||||
Name: "a telegram receiver", |
||||
Type: "telegram", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"autoResolve": true, |
||||
"chatid": "12345", |
||||
"httpMethod": "POST", |
||||
"severity": "critical", |
||||
"uploadImage": false |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{ |
||||
"bottoken": "<bottoken>", |
||||
}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var telegramReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&telegramReceiver)) |
||||
|
||||
var threemaReceiver = models.AlertNotification{ |
||||
Id: 17, |
||||
Uid: "threema UID", |
||||
OrgId: 1, |
||||
Name: "a threema receiver", |
||||
Type: "threema", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"autoResolve": true, |
||||
"gateway_id": "*3MAGWID", |
||||
"httpMethod": "POST", |
||||
"recipient_id": "YOUR3MID", |
||||
"severity": "critical", |
||||
"uploadImage": false |
||||
},`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{ |
||||
"api_secret": "<api_secret>", |
||||
}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var threemaDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&threemaReceiver)) |
||||
|
||||
var victoropsReceiver = models.AlertNotification{ |
||||
Id: 18, |
||||
Uid: "victorops UID", |
||||
OrgId: 1, |
||||
Name: "a victorops receiver", |
||||
Type: "victorops", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`{ |
||||
"autoResolve": true, |
||||
"httpMethod": "POST", |
||||
"severity": "critical", |
||||
"uploadImage": false, |
||||
"url": "http://" |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var victoropsReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&victoropsReceiver)) |
||||
|
||||
var webhookReceiver = models.AlertNotification{ |
||||
Id: 19, |
||||
Uid: "webhook UID", |
||||
OrgId: 1, |
||||
Name: "a webhook receiver", |
||||
Type: "webhook", |
||||
SendReminder: false, |
||||
DisableResolveMessage: false, |
||||
Frequency: 5 * time.Minute, |
||||
IsDefault: false, |
||||
Settings: toSimpleJSON(`x{ |
||||
"autoResolve": true, |
||||
"httpMethod": "POST", |
||||
"password": "", |
||||
"severity": "critical", |
||||
"uploadImage": true, |
||||
"url": "http://localhost:3010", |
||||
"username": "" |
||||
}`), |
||||
SecureSettings: securejsondata.GetEncryptedJsonData(map[string]string{ |
||||
"password": "<password>", |
||||
}), |
||||
Created: time.Now().Add(-time.Hour), |
||||
Updated: time.Now().Add(-5 * time.Minute), |
||||
} |
||||
var webhookReceiverDTO = apimodels.GettableGrafanaReceiver(*dtos.NewAlertNotification(&webhookReceiver)) |
||||
|
||||
type AlertmanagerApiMock struct { |
||||
log log.Logger |
||||
} |
||||
|
||||
func (mock AlertmanagerApiMock) RouteCreateSilence(c *models.ReqContext, body apimodels.CreateSilenceParams) response.Response { |
||||
recipient := c.Params(":Recipient") |
||||
mock.log.Info("RouteCreateSilence: ", "Recipient", recipient) |
||||
mock.log.Info("RouteCreateSilence: ", "body", body) |
||||
return response.JSON(http.StatusAccepted, util.DynMap{"message": "silence created"}) |
||||
} |
||||
|
||||
func (mock AlertmanagerApiMock) RouteDeleteAlertingConfig(c *models.ReqContext) response.Response { |
||||
recipient := c.Params(":Recipient") |
||||
mock.log.Info("RouteDeleteAlertingConfig: ", "Recipient", recipient) |
||||
return response.JSON(http.StatusOK, util.DynMap{"message": "config deleted"}) |
||||
} |
||||
|
||||
func (mock AlertmanagerApiMock) RouteDeleteSilence(c *models.ReqContext) response.Response { |
||||
silenceID := c.Params(":SilenceId") |
||||
mock.log.Info("RouteDeleteSilence: ", "SilenceId", silenceID) |
||||
recipient := c.Params(":Recipient") |
||||
mock.log.Info("RouteDeleteSilence: ", "Recipient", recipient) |
||||
return response.JSON(http.StatusOK, util.DynMap{"message": "silence deleted"}) |
||||
} |
||||
|
||||
func (mock AlertmanagerApiMock) RouteGetAlertingConfig(c *models.ReqContext) response.Response { |
||||
recipient := c.Params(":Recipient") |
||||
mock.log.Info("RouteGetAlertingConfig: ", "Recipient", recipient) |
||||
// now := time.Now()
|
||||
result := apimodels.GettableUserConfig{ |
||||
TemplateFiles: map[string]string{ |
||||
"tmpl1": "val1", |
||||
"tmpl2": "val2", |
||||
}, |
||||
AlertmanagerConfig: apimodels.GettableApiAlertingConfig{ |
||||
Config: apimodels.Config{ |
||||
Global: &config.GlobalConfig{}, |
||||
Route: &config.Route{}, |
||||
InhibitRules: []*config.InhibitRule{}, |
||||
Receivers: []*config.Receiver{}, |
||||
Templates: []string{}, |
||||
}, |
||||
Receivers: []*apimodels.GettableApiReceiver{ |
||||
{ |
||||
GettableGrafanaReceivers: apimodels.GettableGrafanaReceivers{ |
||||
GrafanaManagedReceivers: []*apimodels.GettableGrafanaReceiver{ |
||||
&alertmanagerReceiverDTO, |
||||
&dingdingReceiverDTO, |
||||
&discordReceiverDTO, |
||||
&emailReceiverDTO, |
||||
&googlechatReceiverDTOs, |
||||
&hipchatReceiverDTO, |
||||
&kafkaReceiverDTO, |
||||
&lineReceiverDTO, |
||||
&opsgenieReceiverDTO, |
||||
&pagerdutyReceiverDTO, |
||||
&pushoverReceiverDTO, |
||||
&sensuReceiverDTO, |
||||
&sensugoReceiverDTO, |
||||
&slackReceiverDTO, |
||||
&teamsReceiverDTO, |
||||
&telegramReceiverDTO, |
||||
&threemaDTO, |
||||
&victoropsReceiverDTO, |
||||
&webhookReceiverDTO, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
} |
||||
return response.JSON(http.StatusOK, result) |
||||
} |
||||
|
||||
func (mock AlertmanagerApiMock) RouteGetAMAlertGroups(c *models.ReqContext) response.Response { |
||||
recipient := c.Params(":Recipient") |
||||
mock.log.Info("RouteGetAMAlertGroups: ", "Recipient", recipient) |
||||
now := time.Now() |
||||
result := apimodels.AlertGroups{ |
||||
&amv2.AlertGroup{ |
||||
Alerts: []*amv2.GettableAlert{ |
||||
{ |
||||
Annotations: amv2.LabelSet{ |
||||
"annotation1-1": "value1", |
||||
"annotation1-2": "value2", |
||||
}, |
||||
EndsAt: timePtr(strfmt.DateTime(now.Add(time.Hour))), |
||||
Fingerprint: stringPtr("fingerprint 1"), |
||||
Receivers: []*amv2.Receiver{ |
||||
{ |
||||
Name: stringPtr("receiver identifier 1-1"), |
||||
}, |
||||
{ |
||||
Name: stringPtr("receiver identifier 1-2"), |
||||
}, |
||||
}, |
||||
StartsAt: timePtr(strfmt.DateTime(now)), |
||||
Status: &amv2.AlertStatus{ |
||||
InhibitedBy: []string{"inhibitedBy 1"}, |
||||
SilencedBy: []string{"silencedBy 1"}, |
||||
State: stringPtr(amv2.AlertStatusStateActive), |
||||
}, |
||||
UpdatedAt: timePtr(strfmt.DateTime(now.Add(-time.Hour))), |
||||
Alert: amv2.Alert{ |
||||
GeneratorURL: strfmt.URI("a URL"), |
||||
Labels: amv2.LabelSet{ |
||||
"label1-1": "value1", |
||||
"label1-2": "value2", |
||||
}, |
||||
}, |
||||
}, |
||||
{ |
||||
Annotations: amv2.LabelSet{ |
||||
"annotation2-1": "value1", |
||||
"annotation2-2": "value2", |
||||
}, |
||||
EndsAt: timePtr(strfmt.DateTime(now.Add(time.Hour))), |
||||
Fingerprint: stringPtr("fingerprint 2"), |
||||
Receivers: []*amv2.Receiver{ |
||||
{ |
||||
Name: stringPtr("receiver identifier 2-1"), |
||||
}, |
||||
{ |
||||
Name: stringPtr("receiver identifier 2-2"), |
||||
}, |
||||
}, |
||||
StartsAt: timePtr(strfmt.DateTime(now)), |
||||
Status: &amv2.AlertStatus{ |
||||
InhibitedBy: []string{"inhibitedBy 2"}, |
||||
SilencedBy: []string{"silencedBy 2"}, |
||||
State: stringPtr(amv2.AlertStatusStateActive), |
||||
}, |
||||
UpdatedAt: timePtr(strfmt.DateTime(now.Add(-time.Hour))), |
||||
Alert: amv2.Alert{ |
||||
GeneratorURL: strfmt.URI("a URL"), |
||||
Labels: amv2.LabelSet{ |
||||
"label2-1": "value1", |
||||
"label2-2": "value2", |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
Labels: amv2.LabelSet{ |
||||
"label1-1": "value1", |
||||
"label1-2": "value2", |
||||
}, |
||||
Receiver: &amv2.Receiver{ |
||||
Name: stringPtr("receiver identifier 2-1"), |
||||
}, |
||||
}, |
||||
&amv2.AlertGroup{ |
||||
Alerts: []*amv2.GettableAlert{ |
||||
{ |
||||
Annotations: amv2.LabelSet{ |
||||
"annotation2-1": "value1", |
||||
"annotation2-2": "value2", |
||||
}, |
||||
EndsAt: timePtr(strfmt.DateTime(now.Add(time.Hour))), |
||||
Fingerprint: stringPtr("fingerprint 2"), |
||||
Receivers: []*amv2.Receiver{ |
||||
{ |
||||
Name: stringPtr("receiver identifier 2-1"), |
||||
}, |
||||
{ |
||||
Name: stringPtr("receiver identifier 2-2"), |
||||
}, |
||||
}, |
||||
StartsAt: timePtr(strfmt.DateTime(now)), |
||||
Status: &amv2.AlertStatus{ |
||||
InhibitedBy: []string{"inhibitedBy 2"}, |
||||
SilencedBy: []string{"silencedBy 2"}, |
||||
State: stringPtr(amv2.AlertStatusStateActive), |
||||
}, |
||||
UpdatedAt: timePtr(strfmt.DateTime(now.Add(-time.Hour))), |
||||
Alert: amv2.Alert{ |
||||
GeneratorURL: strfmt.URI("a URL"), |
||||
Labels: amv2.LabelSet{ |
||||
"label2-1": "value1", |
||||
"label2-2": "value2", |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
Labels: amv2.LabelSet{ |
||||
"label2-1": "value1", |
||||
"label2-2": "value2", |
||||
}, |
||||
Receiver: &amv2.Receiver{ |
||||
Name: stringPtr("receiver identifier 2-1"), |
||||
}, |
||||
}, |
||||
} |
||||
return response.JSON(http.StatusOK, result) |
||||
} |
||||
|
||||
func (mock AlertmanagerApiMock) RouteGetAMAlerts(c *models.ReqContext) response.Response { |
||||
recipient := c.Params(":Recipient") |
||||
mock.log.Info("RouteGetAMAlerts: ", "Recipient", recipient) |
||||
now := time.Now() |
||||
result := apimodels.GettableAlerts{ |
||||
&amv2.GettableAlert{ |
||||
Annotations: amv2.LabelSet{ |
||||
"annotation1-1": "value1", |
||||
"annotation1-2": "value2", |
||||
}, |
||||
EndsAt: timePtr(strfmt.DateTime(now.Add(time.Hour))), |
||||
Fingerprint: stringPtr("fingerprint 1"), |
||||
Receivers: []*amv2.Receiver{ |
||||
{ |
||||
Name: stringPtr("receiver identifier 1-1"), |
||||
}, |
||||
{ |
||||
Name: stringPtr("receiver identifier 1-2"), |
||||
}, |
||||
}, |
||||
StartsAt: timePtr(strfmt.DateTime(now)), |
||||
Status: &amv2.AlertStatus{ |
||||
InhibitedBy: []string{"inhibitedBy 1"}, |
||||
SilencedBy: []string{"silencedBy 1"}, |
||||
State: stringPtr(amv2.AlertStatusStateActive), |
||||
}, |
||||
UpdatedAt: timePtr(strfmt.DateTime(now.Add(-time.Hour))), |
||||
Alert: amv2.Alert{ |
||||
GeneratorURL: strfmt.URI("a URL"), |
||||
Labels: amv2.LabelSet{ |
||||
"label1-1": "value1", |
||||
"label1-2": "value2", |
||||
}, |
||||
}, |
||||
}, |
||||
&amv2.GettableAlert{ |
||||
Annotations: amv2.LabelSet{ |
||||
"annotation2-1": "value1", |
||||
"annotation2-2": "value2", |
||||
}, |
||||
EndsAt: timePtr(strfmt.DateTime(now.Add(time.Hour))), |
||||
Fingerprint: stringPtr("fingerprint 2"), |
||||
Receivers: []*amv2.Receiver{ |
||||
{ |
||||
Name: stringPtr("receiver identifier 2-1"), |
||||
}, |
||||
{ |
||||
Name: stringPtr("receiver identifier 2-2"), |
||||
}, |
||||
}, |
||||
StartsAt: timePtr(strfmt.DateTime(now)), |
||||
Status: &amv2.AlertStatus{ |
||||
InhibitedBy: []string{"inhibitedBy 2"}, |
||||
SilencedBy: []string{"silencedBy 2"}, |
||||
State: stringPtr(amv2.AlertStatusStateActive), |
||||
}, |
||||
UpdatedAt: timePtr(strfmt.DateTime(now.Add(-time.Hour))), |
||||
Alert: amv2.Alert{ |
||||
GeneratorURL: strfmt.URI("a URL"), |
||||
Labels: amv2.LabelSet{ |
||||
"label2-1": "value1", |
||||
"label2-2": "value2", |
||||
}, |
||||
}, |
||||
}, |
||||
} |
||||
return response.JSON(http.StatusOK, result) |
||||
} |
||||
|
||||
func (mock AlertmanagerApiMock) RouteGetSilence(c *models.ReqContext) response.Response { |
||||
silenceID := c.Params(":SilenceId") |
||||
mock.log.Info("RouteGetSilence: ", "SilenceId", silenceID) |
||||
recipient := c.Params(":Recipient") |
||||
mock.log.Info("RouteGetSilence: ", "Recipient", recipient) |
||||
now := time.Now() |
||||
result := apimodels.GettableSilence{ |
||||
ID: stringPtr("id"), |
||||
Status: &amv2.SilenceStatus{ |
||||
State: stringPtr("active"), |
||||
}, |
||||
UpdatedAt: timePtr(strfmt.DateTime(now.Add(-time.Hour))), |
||||
Silence: amv2.Silence{ |
||||
Comment: stringPtr("comment"), |
||||
CreatedBy: stringPtr("created by"), |
||||
EndsAt: timePtr(strfmt.DateTime(now.Add(time.Hour))), |
||||
StartsAt: timePtr(strfmt.DateTime(now)), |
||||
Matchers: []*amv2.Matcher{ |
||||
{ |
||||
IsRegex: boolPtr(false), |
||||
Name: stringPtr("name"), |
||||
Value: stringPtr("value"), |
||||
}, |
||||
{ |
||||
IsRegex: boolPtr(false), |
||||
Name: stringPtr("name2"), |
||||
Value: stringPtr("value2"), |
||||
}, |
||||
}, |
||||
}, |
||||
} |
||||
return response.JSON(http.StatusOK, result) |
||||
} |
||||
|
||||
func (mock AlertmanagerApiMock) RouteGetSilences(c *models.ReqContext) response.Response { |
||||
recipient := c.Params(":Recipient") |
||||
mock.log.Info("RouteGetSilences: ", "Recipient", recipient) |
||||
now := time.Now() |
||||
result := apimodels.GettableSilences{ |
||||
&amv2.GettableSilence{ |
||||
ID: stringPtr("silence1"), |
||||
Status: &amv2.SilenceStatus{ |
||||
State: stringPtr("active"), |
||||
}, |
||||
UpdatedAt: timePtr(strfmt.DateTime(now.Add(-time.Hour))), |
||||
Silence: amv2.Silence{ |
||||
Comment: stringPtr("silence1 comment"), |
||||
CreatedBy: stringPtr("silence1 created by"), |
||||
EndsAt: timePtr(strfmt.DateTime(now.Add(time.Hour))), |
||||
StartsAt: timePtr(strfmt.DateTime(now)), |
||||
Matchers: []*amv2.Matcher{ |
||||
{ |
||||
IsRegex: boolPtr(false), |
||||
Name: stringPtr("silence1 name"), |
||||
Value: stringPtr("silence1 value"), |
||||
}, |
||||
{ |
||||
IsRegex: boolPtr(true), |
||||
Name: stringPtr("silence1 name2"), |
||||
Value: stringPtr("silence1 value2"), |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
&amv2.GettableSilence{ |
||||
ID: stringPtr("silence2"), |
||||
Status: &amv2.SilenceStatus{ |
||||
State: stringPtr("pending"), |
||||
}, |
||||
UpdatedAt: timePtr(strfmt.DateTime(now.Add(-time.Hour))), |
||||
Silence: amv2.Silence{ |
||||
Comment: stringPtr("silence2 comment"), |
||||
CreatedBy: stringPtr("silence2 created by"), |
||||
EndsAt: timePtr(strfmt.DateTime(now.Add(time.Hour))), |
||||
StartsAt: timePtr(strfmt.DateTime(now)), |
||||
Matchers: []*amv2.Matcher{ |
||||
{ |
||||
IsRegex: boolPtr(false), |
||||
Name: stringPtr("silence2 name"), |
||||
Value: stringPtr("silence2 value"), |
||||
}, |
||||
{ |
||||
IsRegex: boolPtr(true), |
||||
Name: stringPtr("silence2 name2"), |
||||
Value: stringPtr("silence2 value2"), |
||||
}, |
||||
}, |
||||
}, |
||||
}, |
||||
} |
||||
return response.JSON(http.StatusOK, result) |
||||
} |
||||
|
||||
func (mock AlertmanagerApiMock) RoutePostAlertingConfig(c *models.ReqContext, body apimodels.PostableUserConfig) response.Response { |
||||
recipient := c.Params(":Recipient") |
||||
mock.log.Info("RoutePostAlertingConfig: ", "Recipient", recipient) |
||||
mock.log.Info("RoutePostAlertingConfig: ", "body", body) |
||||
return response.JSON(http.StatusAccepted, util.DynMap{"message": "configuration created"}) |
||||
} |
||||
|
||||
func (mock AlertmanagerApiMock) RoutePostAMAlerts(c *models.ReqContext, body apimodels.PostableAlerts) response.Response { |
||||
recipient := c.Params(":Recipient") |
||||
mock.log.Info("RoutePostAMAlerts: ", "Recipient", recipient) |
||||
mock.log.Info("RoutePostAMAlerts: ", "body", body) |
||||
return response.JSON(http.StatusOK, util.DynMap{"message": "alerts created"}) |
||||
} |
||||
@ -0,0 +1,119 @@ |
||||
package models |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
|
||||
"github.com/go-openapi/strfmt" |
||||
|
||||
amv2 "github.com/prometheus/alertmanager/api/v2/models" |
||||
) |
||||
|
||||
var ( |
||||
// ErrSilenceNotFound is an error for an unknown silence.
|
||||
ErrSilenceNotFound = fmt.Errorf("could not find silence") |
||||
// ErrSilenceFailedGenerateUniqueUID is an error for failure to generate silence UID
|
||||
ErrSilenceFailedGenerateUniqueUID = errors.New("failed to generate silence UID") |
||||
) |
||||
|
||||
type SilenceSettings amv2.GettableSilence |
||||
|
||||
type SilenceStatus amv2.SilenceStatus |
||||
|
||||
// FromDB loads silence status stored in the database.
|
||||
// FromDB is part of the xorm Conversion interface.
|
||||
func (st *SilenceStatus) FromDB(b []byte) error { |
||||
str := string(b) |
||||
*st = SilenceStatus{State: &str} |
||||
return nil |
||||
} |
||||
|
||||
// ToDB serializes silence status to be stored in the database.
|
||||
// ToDB is part of the xorm Conversion interface.
|
||||
func (st *SilenceStatus) ToDB() ([]byte, error) { |
||||
return []byte(*st.State), nil |
||||
} |
||||
|
||||
type Matchers amv2.Matchers |
||||
|
||||
// FromDB loads matchers stored in the database.
|
||||
// FromDB is part of the xorm Conversion interface.
|
||||
func (m *Matchers) FromDB(b []byte) error { |
||||
err := json.Unmarshal(b, &m) |
||||
if err != nil { |
||||
return fmt.Errorf("failed to convert matchers from database: %w", err) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// ToDB serializes matchers to be stored in the database.
|
||||
// ToDB is part of the xorm Conversion interface.
|
||||
func (m *Matchers) ToDB() ([]byte, error) { |
||||
blobMatchers, err := json.Marshal(m) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("failed to convert matchers to send to the database: %w", err) |
||||
} |
||||
return blobMatchers, nil |
||||
} |
||||
|
||||
type Silence struct { |
||||
ID int64 `xorm:"pk autoincr 'id'"` |
||||
OrgID int64 `xorm:"org_id" json:"orgId"` |
||||
UID string `xorm:"uid" json:"uid"` |
||||
Status SilenceStatus `json:"status"` |
||||
UpdatedAt strfmt.DateTime `json:"updatedAt"` |
||||
Comment string `json:"comment"` |
||||
CreatedBy string `json:"createdBy"` |
||||
EndsAt strfmt.DateTime `json:"endsAt"` |
||||
Matchers Matchers `json:"matchers"` |
||||
StartsAt strfmt.DateTime `json:"startsAt"` |
||||
} |
||||
|
||||
func (s Silence) ToGettableSilence() amv2.GettableSilence { |
||||
gettableSilence := amv2.GettableSilence{ |
||||
ID: &s.UID, |
||||
Status: &amv2.SilenceStatus{State: s.Status.State}, |
||||
UpdatedAt: &s.UpdatedAt, |
||||
} |
||||
gettableSilence.Comment = &s.Comment |
||||
gettableSilence.CreatedBy = &s.CreatedBy |
||||
gettableSilence.EndsAt = &s.EndsAt |
||||
gettableSilence.Matchers = amv2.Matchers(s.Matchers) |
||||
gettableSilence.StartsAt = &s.StartsAt |
||||
return gettableSilence |
||||
} |
||||
|
||||
type SaveSilenceCommand struct { |
||||
amv2.Silence |
||||
UID string |
||||
OrgID int64 |
||||
} |
||||
|
||||
type DeleteSilenceByUIDCommand struct { |
||||
UID string |
||||
OrgID int64 |
||||
} |
||||
|
||||
type DeleteSilenceByIDCommand struct { |
||||
ID int64 |
||||
} |
||||
|
||||
type GetSilenceByUIDQuery struct { |
||||
UID string |
||||
OrgID int64 |
||||
|
||||
Result *Silence |
||||
} |
||||
|
||||
type GetSilenceByIDQuery struct { |
||||
ID int64 |
||||
|
||||
Result *Silence |
||||
} |
||||
|
||||
type GetSilencesQuery struct { |
||||
OrgID int64 |
||||
|
||||
Result []*Silence |
||||
} |
||||
@ -0,0 +1,165 @@ |
||||
package store |
||||
|
||||
import ( |
||||
"context" |
||||
"errors" |
||||
"fmt" |
||||
|
||||
"github.com/go-openapi/strfmt" |
||||
"github.com/grafana/grafana/pkg/services/ngalert/models" |
||||
"github.com/grafana/grafana/pkg/services/sqlstore" |
||||
"github.com/grafana/grafana/pkg/util" |
||||
amv2 "github.com/prometheus/alertmanager/api/v2/models" |
||||
) |
||||
|
||||
func getSilenceByUID(sess *sqlstore.DBSession, silenceUID string, orgID int64) (*models.Silence, error) { |
||||
silence := &models.Silence{ |
||||
OrgID: orgID, |
||||
UID: silenceUID, |
||||
} |
||||
has, err := sess.Get(silence) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
if !has { |
||||
return nil, models.ErrSilenceNotFound |
||||
} |
||||
return silence, nil |
||||
} |
||||
|
||||
func getSilenceByID(sess *sqlstore.DBSession, id int64) (*models.Silence, error) { |
||||
silence := &models.Silence{} |
||||
|
||||
has, err := sess.ID(id).Get(silence) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
if !has { |
||||
return nil, ErrNoAlertmanagerConfiguration |
||||
} |
||||
|
||||
return silence, nil |
||||
} |
||||
|
||||
func (st DBstore) GetOrgSilences(query *models.GetSilencesQuery) error { |
||||
return st.SQLStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error { |
||||
silences := make([]*models.Silence, 0) |
||||
q := "SELECT * FROM silence WHERE org_id = ?" |
||||
if err := sess.SQL(q, query.OrgID).Find(&silences); err != nil { |
||||
return err |
||||
} |
||||
|
||||
query.Result = silences |
||||
return nil |
||||
}) |
||||
} |
||||
|
||||
func (st DBstore) GetSilenceByUID(query *models.GetSilenceByUIDQuery) error { |
||||
return st.SQLStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error { |
||||
silence, err := getSilenceByUID(sess, query.UID, query.OrgID) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
query.Result = silence |
||||
return nil |
||||
}) |
||||
} |
||||
|
||||
func (st DBstore) GetSilenceByID(query *models.GetSilenceByIDQuery) error { |
||||
return st.SQLStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error { |
||||
silence, err := getSilenceByID(sess, query.ID) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
query.Result = silence |
||||
return nil |
||||
}) |
||||
} |
||||
|
||||
func (st DBstore) DeleteSilenceByUID(cmd *models.DeleteSilenceByUIDCommand) error { |
||||
return st.SQLStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error { |
||||
_, err := getSilenceByUID(sess, cmd.UID, cmd.OrgID) |
||||
if err != nil && errors.Is(err, models.ErrSilenceNotFound) { |
||||
return err |
||||
} |
||||
|
||||
_, err = sess.Exec("DELETE FROM silence WHERE uid = ? AND org_id = ?", cmd.UID, cmd.OrgID) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
return nil |
||||
}) |
||||
} |
||||
|
||||
func (st DBstore) DeleteSilenceByID(cmd *models.DeleteSilenceByIDCommand) error { |
||||
return st.SQLStore.WithTransactionalDbSession(context.Background(), func(sess *sqlstore.DBSession) error { |
||||
_, err := getSilenceByID(sess, cmd.ID) |
||||
if err != nil && errors.Is(err, models.ErrSilenceNotFound) { |
||||
return err |
||||
} |
||||
|
||||
_, err = sess.Exec("DELETE FROM silence WHERE id ?", cmd.ID) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
return nil |
||||
}) |
||||
} |
||||
|
||||
func (st DBstore) SaveSilence(cmd *models.SaveSilenceCommand) error { |
||||
return st.SQLStore.WithTransactionalDbSession(context.Background(), func(sess *sqlstore.DBSession) error { |
||||
var firstSeen bool |
||||
existingSilence, err := getSilenceByUID(sess, cmd.UID, cmd.OrgID) |
||||
if err != nil { |
||||
if !errors.Is(err, models.ErrSilenceNotFound) { |
||||
return err |
||||
} |
||||
firstSeen = true |
||||
} |
||||
|
||||
statusPending := amv2.SilenceStatusStatePending |
||||
updatedAt := strfmt.DateTime(TimeNow()) |
||||
|
||||
silenceModel := models.Silence{ |
||||
OrgID: cmd.OrgID, |
||||
UID: cmd.UID, |
||||
Status: models.SilenceStatus{State: &statusPending}, |
||||
UpdatedAt: updatedAt, |
||||
Comment: *cmd.Comment, |
||||
CreatedBy: *cmd.CreatedBy, |
||||
EndsAt: *cmd.EndsAt, |
||||
Matchers: models.Matchers(cmd.Matchers), |
||||
StartsAt: *cmd.StartsAt, |
||||
} |
||||
|
||||
switch firstSeen { |
||||
case true: |
||||
if _, err := sess.Insert(&silenceModel); err != nil { |
||||
return fmt.Errorf("failed to insert silence: %w", err) |
||||
} |
||||
default: |
||||
if _, err := sess.ID(existingSilence.ID).Update(&silenceModel); err != nil { |
||||
return fmt.Errorf("failed to update silence: %w", err) |
||||
} |
||||
} |
||||
|
||||
return nil |
||||
}) |
||||
} |
||||
|
||||
func GenerateNewSilenceUID(sess *sqlstore.DBSession, orgID int64) (string, error) { |
||||
for i := 0; i < 3; i++ { |
||||
uid := util.GenerateShortUID() |
||||
|
||||
exists, err := sess.Where("org_id=? AND uid=?", orgID, uid).Get(&models.Silence{}) |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
if !exists { |
||||
return uid, nil |
||||
} |
||||
} |
||||
|
||||
return "", models.ErrSilenceFailedGenerateUniqueUID |
||||
} |
||||
Loading…
Reference in new issue