mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
[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>
This commit is contained in:
parent
b0ffcfd558
commit
a5e95823b2
2
go.mod
2
go.mod
@ -40,7 +40,7 @@ require (
|
||||
github.com/google/go-cmp v0.5.5
|
||||
github.com/google/uuid v1.2.0
|
||||
github.com/gosimple/slug v1.9.0
|
||||
github.com/grafana/alerting-api v0.0.0-20210330162237-0b5408c529a8
|
||||
github.com/grafana/alerting-api v0.0.0-20210331130828-17c19ddf88ee
|
||||
github.com/grafana/grafana-aws-sdk v0.4.0
|
||||
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.90.0
|
||||
|
4
go.sum
4
go.sum
@ -798,6 +798,8 @@ github.com/gosimple/slug v1.9.0 h1:r5vDcYrFz9BmfIAMC829un9hq7hKM4cHUrsv36LbEqs=
|
||||
github.com/gosimple/slug v1.9.0/go.mod h1:AMZ+sOVe65uByN3kgEyf9WEBKBCSS+dJjMX9x4vDJbg=
|
||||
github.com/grafana/alerting-api v0.0.0-20210330162237-0b5408c529a8 h1:okhEX26LU7AGN/3C8NDWfdjBmKclvoFvJz9o/LsNcK8=
|
||||
github.com/grafana/alerting-api v0.0.0-20210330162237-0b5408c529a8/go.mod h1:5IppnPguSHcCbVLGCVzVjBvuQZNbYgVJ4KyXXjhCyWY=
|
||||
github.com/grafana/alerting-api v0.0.0-20210331130828-17c19ddf88ee h1:jpZdUOta4PK3CH3+2UCuzqn1SGZ+dQj+dWH45B0c1aI=
|
||||
github.com/grafana/alerting-api v0.0.0-20210331130828-17c19ddf88ee/go.mod h1:5IppnPguSHcCbVLGCVzVjBvuQZNbYgVJ4KyXXjhCyWY=
|
||||
github.com/grafana/go-mssqldb v0.0.0-20210326084033-d0ce3c521036 h1:GplhUk6Xes5JIhUUrggPcPBhOn+eT8+WsHiebvq7GgA=
|
||||
github.com/grafana/go-mssqldb v0.0.0-20210326084033-d0ce3c521036/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/grafana/grafana v1.9.2-0.20210308201921-4ce0a49eac03/go.mod h1:AHRRvd4utJGY25J5nW8aL7wZzn/LcJ0z2za9oOp14j4=
|
||||
@ -1335,6 +1337,7 @@ github.com/pquerna/cachecontrol v0.0.0-20200819021114-67c6ae64274f/go.mod h1:hoL
|
||||
github.com/prometheus/alertmanager v0.18.0/go.mod h1:WcxHBl40VSPuOaqWae6l6HpnEOVRIycEJ7i9iYkadEE=
|
||||
github.com/prometheus/alertmanager v0.19.0/go.mod h1:Eyp94Yi/T+kdeb2qvq66E3RGuph5T/jm/RBVh4yz1xo=
|
||||
github.com/prometheus/alertmanager v0.20.0/go.mod h1:9g2i48FAyZW6BtbsnvHtMHQXl2aVtrORKwKVCQ+nbrg=
|
||||
github.com/prometheus/alertmanager v0.21.0 h1:qK51JcUR9l/unhawGA9F9B64OCYfcGewhPNprem/Acc=
|
||||
github.com/prometheus/alertmanager v0.21.0/go.mod h1:h7tJ81NA0VLWvWEayi1QltevFkLF3KxmC/malTcT8Go=
|
||||
github.com/prometheus/alertmanager v0.21.1-0.20200911160112-1fdff6b3f939/go.mod h1:imXRHOP6QTsE0fFsIsAV/cXimS32m7gVZOiUj11m6Ig=
|
||||
github.com/prometheus/alertmanager v0.21.1-0.20210211203738-a7ca7b1d2951/go.mod h1:6Yc2n2ap5/oP99x1yN6Ho+yL0w8a0oClIR5xxW/JLGs=
|
||||
@ -1421,6 +1424,7 @@ github.com/prometheus/prometheus v1.8.2-0.20210217141258-a6be548dbc17 h1:VN3p3Nb
|
||||
github.com/prometheus/prometheus v1.8.2-0.20210217141258-a6be548dbc17/go.mod h1:dv3B1syqmkrkmo665MPCU6L8PbTXIiUeg/OEQULLNxA=
|
||||
github.com/prometheus/statsd_exporter v0.15.0/go.mod h1:Dv8HnkoLQkeEjkIE4/2ndAA7WL1zHKK7WMqFQqu72rw=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/quasilyte/go-ruleguard/dsl/fluent v0.0.0-20201222093424-5d7e62a465d3 h1:eL7x4/zMnlquMxYe7V078BD7MGskZ0daGln+SJCVzuY=
|
||||
github.com/quasilyte/go-ruleguard/dsl/fluent v0.0.0-20201222093424-5d7e62a465d3/go.mod h1:P7JlQWFT7jDcFZMtUPQbtGzzzxva3rBn6oIF+LPwFcM=
|
||||
github.com/rafaeljusto/redigomock v0.0.0-20190202135759-257e089e14a1/go.mod h1:JaY6n2sDr+z2WTsXkOmNRUfDy6FN0L6Nk7x06ndm4tY=
|
||||
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ=
|
||||
|
@ -482,3 +482,18 @@ func (j *Json) MustUint64(args ...uint64) uint64 {
|
||||
|
||||
return def
|
||||
}
|
||||
|
||||
// MarshalYAML implements yaml.Marshaller.
|
||||
func (j *Json) MarshalYAML() (interface{}, error) {
|
||||
return j.data, nil
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements yaml.Unmarshaller.
|
||||
func (j *Json) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var data interface{}
|
||||
if err := unmarshal(&data); err != nil {
|
||||
return err
|
||||
}
|
||||
j.data = data
|
||||
return nil
|
||||
}
|
||||
|
@ -30,6 +30,10 @@ var timeNow = time.Now
|
||||
|
||||
type Alertmanager interface {
|
||||
ApplyConfig(config *apimodels.PostableUserConfig) error
|
||||
CreateSilence(ps *apimodels.PostableSilence) (string, error)
|
||||
DeleteSilence(silenceID string) error
|
||||
GetSilence(silenceID string) (apimodels.GettableSilence, error)
|
||||
ListSilences(filters []string) (apimodels.GettableSilences, error)
|
||||
}
|
||||
|
||||
// API handlers.
|
||||
@ -40,6 +44,7 @@ type API struct {
|
||||
DataService *tsdb.Service
|
||||
Schedule schedule.ScheduleService
|
||||
Store store.Store
|
||||
AlertingStore store.AlertingStore
|
||||
DataProxy *datasourceproxy.DatasourceProxyService
|
||||
Alertmanager Alertmanager
|
||||
}
|
||||
@ -53,7 +58,7 @@ func (api *API) RegisterAPIEndpoints() {
|
||||
api.RegisterAlertmanagerApiEndpoints(NewForkedAM(
|
||||
api.DatasourceCache,
|
||||
NewLotexAM(proxy, logger),
|
||||
AlertmanagerApiMock{log: logger},
|
||||
AlertmanagerSrv{store: api.AlertingStore, am: api.Alertmanager, log: logger},
|
||||
))
|
||||
api.RegisterPrometheusApiEndpoints(NewForkedProm(
|
||||
api.DatasourceCache,
|
||||
|
359
pkg/services/ngalert/api/api_alertmanager.go
Normal file
359
pkg/services/ngalert/api/api_alertmanager.go
Normal file
@ -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)
|
||||
}
|
@ -18,15 +18,14 @@ import (
|
||||
)
|
||||
|
||||
type AlertmanagerApiService interface {
|
||||
RouteCreateSilence(*models.ReqContext, apimodels.CreateSilenceParams) response.Response
|
||||
RouteGetSilences(*models.ReqContext) response.Response
|
||||
RouteGetSilence(*models.ReqContext) response.Response
|
||||
RouteDeleteSilence(*models.ReqContext) response.Response
|
||||
|
||||
RouteCreateSilence(*models.ReqContext, apimodels.PostableSilence) response.Response
|
||||
RouteDeleteAlertingConfig(*models.ReqContext) response.Response
|
||||
RouteDeleteSilence(*models.ReqContext) response.Response
|
||||
RouteGetAMAlertGroups(*models.ReqContext) response.Response
|
||||
RouteGetAMAlerts(*models.ReqContext) response.Response
|
||||
RouteGetAlertingConfig(*models.ReqContext) response.Response
|
||||
RouteGetSilence(*models.ReqContext) response.Response
|
||||
RouteGetSilences(*models.ReqContext) response.Response
|
||||
RoutePostAMAlerts(*models.ReqContext, apimodels.PostableAlerts) response.Response
|
||||
RoutePostAlertingConfig(*models.ReqContext, apimodels.PostableUserConfig) response.Response
|
||||
}
|
||||
@ -37,44 +36,29 @@ type AlertmanagerApiBase struct {
|
||||
|
||||
func (api *API) RegisterAlertmanagerApiEndpoints(srv AlertmanagerApiService) {
|
||||
api.RouteRegister.Group("", func(group routing.RouteRegister) {
|
||||
// Silences
|
||||
group.Post(toMacaronPath("/alertmanager/{Recipient}/api/v2/silences"), binding.Bind(apimodels.CreateSilenceParams{}), routing.Wrap(srv.RouteCreateSilence))
|
||||
group.Get(toMacaronPath("/alertmanager/{Recipient}/api/v2/silences"), routing.Wrap(srv.RouteGetSilences))
|
||||
group.Get(toMacaronPath("/alertmanager/{Recipient}/api/v2/silence/{SilenceId}"), routing.Wrap(srv.RouteGetSilence))
|
||||
group.Post(toMacaronPath("/alertmanager/{Recipient}/api/v2/silences"), binding.Bind(apimodels.PostableSilence{}), routing.Wrap(srv.RouteCreateSilence))
|
||||
group.Delete(toMacaronPath("/alertmanager/{Recipient}/config/api/v1/alerts"), routing.Wrap(srv.RouteDeleteAlertingConfig))
|
||||
group.Delete(toMacaronPath("/alertmanager/{Recipient}/api/v2/silence/{SilenceId}"), routing.Wrap(srv.RouteDeleteSilence))
|
||||
|
||||
// Alerts
|
||||
group.Get(toMacaronPath("/alertmanager/{Recipient}/api/v2/alerts/groups"), routing.Wrap(srv.RouteGetAMAlertGroups))
|
||||
group.Get(toMacaronPath("/alertmanager/{Recipient}/api/v2/alerts"), routing.Wrap(srv.RouteGetAMAlerts))
|
||||
group.Post(toMacaronPath("/alertmanager/{Recipient}/api/v2/alerts"), binding.Bind(apimodels.PostableAlerts{}), routing.Wrap(srv.RoutePostAMAlerts))
|
||||
|
||||
// Configuration
|
||||
group.Delete(toMacaronPath("/alertmanager/{Recipient}/config/api/v1/alerts"), routing.Wrap(srv.RouteDeleteAlertingConfig))
|
||||
group.Get(toMacaronPath("/alertmanager/{Recipient}/config/api/v1/alerts"), routing.Wrap(srv.RouteGetAlertingConfig))
|
||||
group.Get(toMacaronPath("/alertmanager/{Recipient}/api/v2/silence/{SilenceId}"), routing.Wrap(srv.RouteGetSilence))
|
||||
group.Get(toMacaronPath("/alertmanager/{Recipient}/api/v2/silences"), routing.Wrap(srv.RouteGetSilences))
|
||||
group.Post(toMacaronPath("/alertmanager/{Recipient}/api/v2/alerts"), binding.Bind(apimodels.PostableAlerts{}), routing.Wrap(srv.RoutePostAMAlerts))
|
||||
group.Post(toMacaronPath("/alertmanager/{Recipient}/config/api/v1/alerts"), binding.Bind(apimodels.PostableUserConfig{}), routing.Wrap(srv.RoutePostAlertingConfig))
|
||||
})
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteCreateSilence(c *models.ReqContext, params apimodels.CreateSilenceParams) response.Response {
|
||||
func (base AlertmanagerApiBase) RouteCreateSilence(c *models.ReqContext, body apimodels.PostableSilence) response.Response {
|
||||
recipient := c.Params(":Recipient")
|
||||
base.log.Info("RouteCreateSilence: ", "Recipient", recipient)
|
||||
base.log.Info("RouteCreateSilence: ", "params", params)
|
||||
base.log.Info("RouteCreateSilence: ", "body", body)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteGetSilences(c *models.ReqContext) response.Response {
|
||||
func (base AlertmanagerApiBase) RouteDeleteAlertingConfig(c *models.ReqContext) response.Response {
|
||||
recipient := c.Params(":Recipient")
|
||||
base.log.Info("RouteGetSilences: ", "Recipient", recipient)
|
||||
filter := c.Params(":Filter")
|
||||
base.log.Info("RouteGetSilences: ", "params", filter)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteGetSilence(c *models.ReqContext) response.Response {
|
||||
silenceId := c.Params(":SilenceId")
|
||||
base.log.Info("RouteGetSilence: ", "SilenceId", silenceId)
|
||||
recipient := c.Params(":Recipient")
|
||||
base.log.Info("RouteGetSilence: ", "Recipient", recipient)
|
||||
base.log.Info("RouteDeleteAlertingConfig: ", "Recipient", recipient)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
@ -86,12 +70,6 @@ func (base AlertmanagerApiBase) RouteDeleteSilence(c *models.ReqContext) respons
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteDeleteAlertingConfig(c *models.ReqContext) response.Response {
|
||||
recipient := c.Params(":Recipient")
|
||||
base.log.Info("RouteDeleteAlertingConfig: ", "Recipient", recipient)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteGetAMAlertGroups(c *models.ReqContext) response.Response {
|
||||
recipient := c.Params(":Recipient")
|
||||
base.log.Info("RouteGetAMAlertGroups: ", "Recipient", recipient)
|
||||
@ -110,6 +88,20 @@ func (base AlertmanagerApiBase) RouteGetAlertingConfig(c *models.ReqContext) res
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteGetSilence(c *models.ReqContext) response.Response {
|
||||
silenceId := c.Params(":SilenceId")
|
||||
base.log.Info("RouteGetSilence: ", "SilenceId", silenceId)
|
||||
recipient := c.Params(":Recipient")
|
||||
base.log.Info("RouteGetSilence: ", "Recipient", recipient)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RouteGetSilences(c *models.ReqContext) response.Response {
|
||||
recipient := c.Params(":Recipient")
|
||||
base.log.Info("RouteGetSilences: ", "Recipient", recipient)
|
||||
return response.Error(http.StatusNotImplemented, "", nil)
|
||||
}
|
||||
|
||||
func (base AlertmanagerApiBase) RoutePostAMAlerts(c *models.ReqContext, body apimodels.PostableAlerts) response.Response {
|
||||
recipient := c.Params(":Recipient")
|
||||
base.log.Info("RoutePostAMAlerts: ", "Recipient", recipient)
|
||||
|
@ -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"})
|
||||
}
|
@ -38,7 +38,7 @@ func (am *ForkedAMSvc) getService(ctx *models.ReqContext) (AlertmanagerApiServic
|
||||
}
|
||||
}
|
||||
|
||||
func (am *ForkedAMSvc) RouteCreateSilence(ctx *models.ReqContext, body apimodels.CreateSilenceParams) response.Response {
|
||||
func (am *ForkedAMSvc) RouteCreateSilence(ctx *models.ReqContext, body apimodels.PostableSilence) response.Response {
|
||||
s, err := am.getService(ctx)
|
||||
if err != nil {
|
||||
return response.Error(400, err.Error(), nil)
|
||||
|
@ -32,7 +32,7 @@ func NewLotexAM(proxy *AlertingProxy, log log.Logger) *LotexAM {
|
||||
}
|
||||
}
|
||||
|
||||
func (am *LotexAM) RouteCreateSilence(ctx *models.ReqContext, silenceBody apimodels.CreateSilenceParams) response.Response {
|
||||
func (am *LotexAM) RouteCreateSilence(ctx *models.ReqContext, silenceBody apimodels.PostableSilence) response.Response {
|
||||
blob, err := json.Marshal(silenceBody)
|
||||
if err != nil {
|
||||
return response.Error(500, "Failed marshal silence", err)
|
||||
|
@ -10,23 +10,109 @@ GET http://admin:admin@localhost:3000/alertmanager/{{lokiDatasourceID}}/config/a
|
||||
GET http://admin:admin@localhost:3000/alertmanager/{{prometheusDatasourceID}}/config/api/v1/alerts
|
||||
|
||||
###
|
||||
# grafana requests
|
||||
GET http://admin:admin@localhost:3000/alertmanager/{{grafana}}/config/api/v1/alerts
|
||||
|
||||
###
|
||||
DELETE http://admin:admin@localhost:3000/alertmanager/{{grafana}}/config/api/v1/alerts
|
||||
|
||||
###
|
||||
# create AM configuration
|
||||
POST http://admin:admin@localhost:3000/alertmanager/{{grafana}}/config/api/v1/alerts
|
||||
content-type: application/json
|
||||
|
||||
< ./post-user-config.json
|
||||
|
||||
###
|
||||
# get latest AM configuration
|
||||
GET http://admin:admin@localhost:3000/alertmanager/{{grafana}}/config/api/v1/alerts
|
||||
content-type: application/json
|
||||
|
||||
###
|
||||
# delete AM configuration
|
||||
DELETE http://admin:admin@localhost:3000/alertmanager/{{grafana}}/config/api/v1/alerts
|
||||
|
||||
###
|
||||
# create AM alerts
|
||||
POST http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/alerts
|
||||
content-type: application/json
|
||||
|
||||
###
|
||||
# get silences - no silences
|
||||
GET http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silences?Filter=foo="bar"&Filter=bar="foo"
|
||||
|
||||
###
|
||||
# create silence
|
||||
POST http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silences
|
||||
content-type: application/json
|
||||
|
||||
< ./post-silence-data.json
|
||||
{
|
||||
"comment": "string",
|
||||
"createdBy": "string",
|
||||
"endsAt": "2023-03-31T14:17:04.419Z",
|
||||
"matchers": [
|
||||
{
|
||||
"isRegex": true,
|
||||
"name": "string",
|
||||
"value": "string"
|
||||
}
|
||||
],
|
||||
"startsAt": "2021-03-31T13:17:04.419Z"
|
||||
}
|
||||
|
||||
###
|
||||
GET http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silences
|
||||
# update silence - does not exist
|
||||
POST http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silences
|
||||
content-type: application/json
|
||||
|
||||
{
|
||||
"id": "something",
|
||||
"comment": "string",
|
||||
"createdBy": "string",
|
||||
"endsAt": "2023-03-31T14:17:04.419Z",
|
||||
"matchers": [
|
||||
{
|
||||
"isRegex": true,
|
||||
"name": "string",
|
||||
"value": "string"
|
||||
}
|
||||
],
|
||||
"startsAt": "2021-03-31T13:17:04.419Z"
|
||||
}
|
||||
|
||||
###
|
||||
# create silence - bad paylaad - start time must be before end time
|
||||
POST http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silences
|
||||
content-type: application/json
|
||||
|
||||
{
|
||||
"comment": "string",
|
||||
"createdBy": "string",
|
||||
"endsAt": "2019-03-31T14:17:04.419Z",
|
||||
"matchers": [
|
||||
{
|
||||
"isRegex": true,
|
||||
"name": "string",
|
||||
"value": "string"
|
||||
}
|
||||
],
|
||||
"startsAt": "2021-03-31T13:17:04.419Z"
|
||||
}
|
||||
|
||||
###
|
||||
# get silences
|
||||
# @name getSilences
|
||||
GET http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silences
|
||||
|
||||
|
||||
###
|
||||
@silenceID = {{getSilences.response.body.$.[0].id}}
|
||||
|
||||
###
|
||||
# get silence
|
||||
GET http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silence/{{silenceID}}
|
||||
|
||||
###
|
||||
# get silence - unknown
|
||||
GET http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silence/unknown
|
||||
|
||||
###
|
||||
# delete silence
|
||||
DELETE http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silence/{{silenceID}}
|
||||
|
||||
###
|
||||
# delete silence - unknown
|
||||
DELETE http://admin:admin@localhost:3000/alertmanager/{{grafana}}/api/v2/silence/unknown
|
||||
|
@ -8,11 +8,13 @@
|
||||
"resolve_timeout": "1s",
|
||||
"smtp_smarthost": ""
|
||||
},
|
||||
"route": {},
|
||||
"route": {
|
||||
"receiver": "grafana_managed"
|
||||
},
|
||||
"templates": [],
|
||||
"receivers": [
|
||||
{
|
||||
"name": "",
|
||||
"name": "grafana_managed",
|
||||
"grafana_managed_receiver_configs": [
|
||||
{
|
||||
"uid": "alertmanager UID",
|
||||
|
@ -35,10 +35,6 @@ func stringPtr(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
func boolPtr(b bool) *bool {
|
||||
return &b
|
||||
}
|
||||
|
||||
func backendType(ctx *models.ReqContext, cache datasources.CacheService) (apimodels.Backend, error) {
|
||||
recipient := ctx.Params("Recipient")
|
||||
if recipient == apimodels.GrafanaBackend.String() {
|
||||
|
@ -2,6 +2,8 @@ package models
|
||||
|
||||
import "time"
|
||||
|
||||
const AlertConfigurationVersion = 1
|
||||
|
||||
// AlertConfiguration represents a single version of the Alerting Engine Configuration.
|
||||
type AlertConfiguration struct {
|
||||
ID int64 `xorm:"pk autoincr 'id'"`
|
||||
@ -13,7 +15,22 @@ type AlertConfiguration struct {
|
||||
|
||||
// GetLatestAlertmanagerConfigurationQuery is the query to get the latest alertmanager configuration.
|
||||
type GetLatestAlertmanagerConfigurationQuery struct {
|
||||
Result *AlertConfiguration
|
||||
}
|
||||
|
||||
// GetAlertmanagerConfigurationQuery is the query to get the latest alertmanager configuration.
|
||||
type GetAlertmanagerConfigurationQuery struct {
|
||||
ID int64
|
||||
|
||||
Result *AlertConfiguration
|
||||
}
|
||||
|
||||
// SaveAlertmanagerConfigurationCmd is the command to save an alertmanager configuration.
|
||||
type SaveAlertmanagerConfigurationCmd struct {
|
||||
AlertmanagerConfiguration string
|
||||
ConfigurationVersion string
|
||||
}
|
||||
|
||||
type DeleteAlertmanagerConfigurationCmd struct {
|
||||
ID int64
|
||||
}
|
||||
|
119
pkg/services/ngalert/models/silence.go
Normal file
119
pkg/services/ngalert/models/silence.go
Normal file
@ -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
|
||||
}
|
@ -81,6 +81,7 @@ func (ng *AlertNG) Init() error {
|
||||
Schedule: ng.schedule,
|
||||
DataProxy: ng.DataProxy,
|
||||
Store: store,
|
||||
AlertingStore: store,
|
||||
Alertmanager: ng.Alertmanager,
|
||||
}
|
||||
api.RegisterAPIEndpoints()
|
||||
@ -99,7 +100,6 @@ func (ng *AlertNG) IsDisabled() bool {
|
||||
if ng.Cfg == nil {
|
||||
return true
|
||||
}
|
||||
// Check also about expressions?
|
||||
return !ng.Cfg.IsNgAlertEnabled()
|
||||
}
|
||||
|
||||
@ -109,8 +109,11 @@ func (ng *AlertNG) AddMigration(mg *migrator.Migrator) {
|
||||
if ng.IsDisabled() {
|
||||
return
|
||||
}
|
||||
addAlertDefinitionMigrations(mg)
|
||||
addAlertDefinitionVersionMigrations(mg)
|
||||
store.AddAlertDefinitionMigrations(mg, defaultIntervalSeconds)
|
||||
store.AddAlertDefinitionVersionMigrations(mg)
|
||||
// Create alert_instance table
|
||||
alertInstanceMigration(mg)
|
||||
store.AlertInstanceMigration(mg)
|
||||
|
||||
// Create silence table
|
||||
store.SilenceMigration(mg)
|
||||
}
|
||||
|
@ -2,10 +2,15 @@ package notifier
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/components/securejsondata"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
|
||||
gokit_log "github.com/go-kit/kit/log"
|
||||
"github.com/grafana/alerting-api/pkg/api"
|
||||
"github.com/pkg/errors"
|
||||
@ -20,7 +25,7 @@ import (
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/registry"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier/channels"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/store"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
@ -61,7 +66,10 @@ func init() {
|
||||
}
|
||||
|
||||
func (am *Alertmanager) IsDisabled() bool {
|
||||
return !setting.AlertingEnabled || !setting.ExecuteAlerts
|
||||
if am.Settings == nil {
|
||||
return true
|
||||
}
|
||||
return !am.Settings.IsNgAlertEnabled()
|
||||
}
|
||||
|
||||
func (am *Alertmanager) Init() (err error) {
|
||||
@ -146,7 +154,7 @@ func (am *Alertmanager) SyncAndApplyConfigFromDatabase() error {
|
||||
|
||||
func (am *Alertmanager) getConfigFromDatabase() (*api.PostableUserConfig, error) {
|
||||
// First, let's get the configuration we need from the database.
|
||||
q := &models.GetLatestAlertmanagerConfigurationQuery{}
|
||||
q := &ngmodels.GetLatestAlertmanagerConfigurationQuery{}
|
||||
if err := am.Store.GetLatestAlertmanagerConfiguration(q); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -233,7 +241,22 @@ func (am *Alertmanager) buildReceiverIntegrations(receiver *api.PostableApiRecei
|
||||
for i, r := range receiver.GrafanaManagedReceivers {
|
||||
switch r.Type {
|
||||
case "email":
|
||||
n, err := channels.NewEmailNotifier(r.Result)
|
||||
frequency, err := time.ParseDuration(r.Frequency)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse receiver frequency %s, %w", r.Frequency, err)
|
||||
}
|
||||
notification := models.AlertNotification{
|
||||
Uid: r.Uid,
|
||||
Name: r.Name,
|
||||
Type: r.Type,
|
||||
IsDefault: r.IsDefault,
|
||||
SendReminder: r.SendReminder,
|
||||
DisableResolveMessage: r.DisableResolveMessage,
|
||||
Frequency: frequency,
|
||||
Settings: r.Settings,
|
||||
SecureSettings: securejsondata.GetEncryptedJsonData(r.SecureSettings),
|
||||
}
|
||||
n, err := channels.NewEmailNotifier(¬ification)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func PersistTemplates(cfg *api.PostableUserConfig, path string) ([]string, bool, error) {
|
||||
@ -78,7 +78,7 @@ func PersistTemplates(cfg *api.PostableUserConfig, path string) ([]string, bool,
|
||||
func Load(rawConfig string) (*api.PostableUserConfig, error) {
|
||||
cfg := &api.PostableUserConfig{}
|
||||
|
||||
if err := yaml.UnmarshalStrict([]byte(rawConfig), cfg); err != nil {
|
||||
if err := yaml.Unmarshal([]byte(rawConfig), cfg); err != nil {
|
||||
return nil, errors.Wrap(err, "unable to parse Alertmanager configuration")
|
||||
}
|
||||
|
||||
|
@ -13,22 +13,71 @@ var (
|
||||
ErrNoAlertmanagerConfiguration = fmt.Errorf("could not find an Alertmanager configuration")
|
||||
)
|
||||
|
||||
func getAlertmanagerConfigurationByID(sess *sqlstore.DBSession, id int64) (*models.AlertConfiguration, error) {
|
||||
c := &models.AlertConfiguration{}
|
||||
|
||||
has, err := sess.ID(id).Get(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !has {
|
||||
return nil, ErrNoAlertmanagerConfiguration
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func getLatestAlertmanagerConfiguration(sess *sqlstore.DBSession) (*models.AlertConfiguration, 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 nil, err
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return nil, ErrNoAlertmanagerConfiguration
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
c, err := getLatestAlertmanagerConfiguration(sess)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return ErrNoAlertmanagerConfiguration
|
||||
}
|
||||
|
||||
query.Result = c
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// GetAlertmanagerConfiguration returns the alertmanager configuration identified by the query.
|
||||
// It returns ErrNoAlertmanagerConfiguration if no such configuration is found.
|
||||
func (st DBstore) GetAlertmanagerConfiguration(query *models.GetAlertmanagerConfigurationQuery) error {
|
||||
return st.SQLStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||
c, err := getAlertmanagerConfigurationByID(sess, query.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
query.Result = c
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// SaveAlertmanagerConfiguration creates an alertmanager configuration.
|
||||
func (st DBstore) SaveAlertmanagerConfiguration(cmd *models.SaveAlertmanagerConfigurationCmd) error {
|
||||
return st.SQLStore.WithDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||
config := models.AlertConfiguration{
|
||||
AlertmanagerConfiguration: cmd.AlertmanagerConfiguration,
|
||||
ConfigurationVersion: cmd.ConfigurationVersion,
|
||||
}
|
||||
if _, err := sess.Insert(config); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
@ -26,20 +26,28 @@ var ErrEmptyTitleError = errors.New("title is empty")
|
||||
type Store interface {
|
||||
DeleteAlertDefinitionByUID(*models.DeleteAlertDefinitionByUIDCommand) error
|
||||
GetAlertDefinitionByUID(*models.GetAlertDefinitionByUIDQuery) error
|
||||
GetAlertDefinitions(query *models.ListAlertDefinitionsQuery) error
|
||||
GetOrgAlertDefinitions(query *models.ListAlertDefinitionsQuery) error
|
||||
GetAlertDefinitions(*models.ListAlertDefinitionsQuery) error
|
||||
GetOrgAlertDefinitions(*models.ListAlertDefinitionsQuery) error
|
||||
SaveAlertDefinition(*models.SaveAlertDefinitionCommand) error
|
||||
UpdateAlertDefinition(*models.UpdateAlertDefinitionCommand) error
|
||||
GetAlertInstance(*models.GetAlertInstanceQuery) error
|
||||
ListAlertInstances(cmd *models.ListAlertInstancesQuery) error
|
||||
SaveAlertInstance(cmd *models.SaveAlertInstanceCommand) error
|
||||
ListAlertInstances(*models.ListAlertInstancesQuery) error
|
||||
SaveAlertInstance(*models.SaveAlertInstanceCommand) error
|
||||
ValidateAlertDefinition(*models.AlertDefinition, bool) error
|
||||
UpdateAlertDefinitionPaused(*models.UpdateAlertDefinitionPausedCommand) error
|
||||
}
|
||||
|
||||
// AlertingStore is the database interface used by the Alertmanager service.
|
||||
type AlertingStore interface {
|
||||
GetLatestAlertmanagerConfiguration(cmd *models.GetLatestAlertmanagerConfigurationQuery) error
|
||||
GetLatestAlertmanagerConfiguration(*models.GetLatestAlertmanagerConfigurationQuery) error
|
||||
GetAlertmanagerConfiguration(*models.GetAlertmanagerConfigurationQuery) error
|
||||
SaveAlertmanagerConfiguration(*models.SaveAlertmanagerConfigurationCmd) error
|
||||
GetOrgSilences(*models.GetSilencesQuery) error
|
||||
GetSilenceByUID(*models.GetSilenceByUIDQuery) error
|
||||
GetSilenceByID(*models.GetSilenceByIDQuery) error
|
||||
SaveSilence(*models.SaveSilenceCommand) error
|
||||
DeleteSilenceByUID(*models.DeleteSilenceByUIDCommand) error
|
||||
DeleteSilenceByID(*models.DeleteSilenceByIDCommand) error
|
||||
}
|
||||
|
||||
// DBstore stores the alert definitions and instances in the database.
|
||||
|
@ -1,4 +1,4 @@
|
||||
package ngalert
|
||||
package store
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -6,7 +6,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
)
|
||||
|
||||
func addAlertDefinitionMigrations(mg *migrator.Migrator) {
|
||||
func AddAlertDefinitionMigrations(mg *migrator.Migrator, defaultIntervalSeconds int64) {
|
||||
mg.AddMigration("delete alert_definition table", migrator.NewDropTableMigration("alert_definition"))
|
||||
|
||||
alertDefinition := migrator.Table{
|
||||
@ -52,7 +52,7 @@ func addAlertDefinitionMigrations(mg *migrator.Migrator) {
|
||||
}))
|
||||
}
|
||||
|
||||
func addAlertDefinitionVersionMigrations(mg *migrator.Migrator) {
|
||||
func AddAlertDefinitionVersionMigrations(mg *migrator.Migrator) {
|
||||
mg.AddMigration("delete alert_definition_version table", migrator.NewDropTableMigration("alert_definition_version"))
|
||||
|
||||
alertDefinitionVersion := migrator.Table{
|
||||
@ -83,7 +83,7 @@ func addAlertDefinitionVersionMigrations(mg *migrator.Migrator) {
|
||||
Mysql("ALTER TABLE alert_definition_version MODIFY data MEDIUMTEXT;"))
|
||||
}
|
||||
|
||||
func alertInstanceMigration(mg *migrator.Migrator) {
|
||||
func AlertInstanceMigration(mg *migrator.Migrator) {
|
||||
alertInstance := migrator.Table{
|
||||
Name: "alert_instance",
|
||||
Columns: []*migrator.Column{
|
||||
@ -107,3 +107,27 @@ 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 SilenceMigration(mg *migrator.Migrator) {
|
||||
silence := migrator.Table{
|
||||
Name: "silence",
|
||||
Columns: []*migrator.Column{
|
||||
{Name: "id", Type: migrator.DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
|
||||
{Name: "org_id", Type: migrator.DB_BigInt, Nullable: false},
|
||||
{Name: "uid", Type: migrator.DB_NVarchar, Length: 190, Nullable: false, Default: "0"},
|
||||
{Name: "comment", Type: migrator.DB_NVarchar, Length: 190, Nullable: true},
|
||||
{Name: "created_by", Type: migrator.DB_NVarchar, Length: 190, Nullable: true},
|
||||
{Name: "matchers", Type: migrator.DB_Text, Nullable: false},
|
||||
{Name: "ends_at", Type: migrator.DB_DateTime, Nullable: false},
|
||||
{Name: "starts_at", Type: migrator.DB_DateTime, Nullable: false},
|
||||
{Name: "updated_at", Type: migrator.DB_DateTime, Nullable: true},
|
||||
{Name: "status", Type: migrator.DB_NVarchar, Length: 8, Nullable: false},
|
||||
},
|
||||
Indices: []*migrator.Index{
|
||||
{Cols: []string{"org_id", "uid"}, Type: migrator.IndexType},
|
||||
},
|
||||
}
|
||||
|
||||
mg.AddMigration("create_silence_table", migrator.NewAddTableMigration(silence))
|
||||
mg.AddMigration("add unique index in silence on org_id and uid columns", migrator.NewAddIndexMigration(silence, silence.Indices[0]))
|
||||
}
|
165
pkg/services/ngalert/store/silence.go
Normal file
165
pkg/services/ngalert/store/silence.go
Normal file
@ -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
Block a user