Merge branch 'master' into alerting_opentsdb
This commit is contained in:
+1
-1
@@ -252,7 +252,7 @@ func NotificationTest(c *middleware.Context, dto dtos.NotificationTestCommand) R
|
||||
return ApiSuccess("Test notification sent")
|
||||
}
|
||||
|
||||
//POST /api/:alertId/pause
|
||||
//POST /api/alerts/:alertId/pause
|
||||
func PauseAlert(c *middleware.Context, dto dtos.PauseAlertCommand) Response {
|
||||
cmd := models.PauseAlertCommand{
|
||||
OrgId: c.OrgId,
|
||||
|
||||
@@ -44,3 +44,19 @@ func GetAnnotations(c *middleware.Context) Response {
|
||||
|
||||
return Json(200, result)
|
||||
}
|
||||
|
||||
func DeleteAnnotations(c *middleware.Context, cmd dtos.DeleteAnnotationsCmd) Response {
|
||||
repo := annotations.GetRepository()
|
||||
|
||||
err := repo.Delete(&annotations.DeleteParams{
|
||||
AlertId: cmd.PanelId,
|
||||
DashboardId: cmd.DashboardId,
|
||||
PanelId: cmd.PanelId,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return ApiError(500, "Failed to delete annotations", err)
|
||||
}
|
||||
|
||||
return ApiSuccess("Annotations deleted")
|
||||
}
|
||||
|
||||
+3
-2
@@ -252,7 +252,7 @@ func Register(r *macaron.Macaron) {
|
||||
|
||||
r.Group("/alerts", func() {
|
||||
r.Post("/test", bind(dtos.AlertTestCommand{}), wrap(AlertTest))
|
||||
r.Post("/:alertId/pause", ValidateOrgAlert, bind(dtos.PauseAlertCommand{}), wrap(PauseAlert))
|
||||
r.Post("/:alertId/pause", bind(dtos.PauseAlertCommand{}), wrap(PauseAlert), reqEditorRole)
|
||||
r.Get("/:alertId", ValidateOrgAlert, wrap(GetAlert))
|
||||
r.Get("/", wrap(GetAlerts))
|
||||
r.Get("/states-for-dashboard", wrap(GetAlertStatesForDashboard))
|
||||
@@ -266,9 +266,10 @@ func Register(r *macaron.Macaron) {
|
||||
r.Put("/:notificationId", bind(m.UpdateAlertNotificationCommand{}), wrap(UpdateAlertNotification))
|
||||
r.Get("/:notificationId", wrap(GetAlertNotificationById))
|
||||
r.Delete("/:notificationId", wrap(DeleteAlertNotification))
|
||||
}, reqOrgAdmin)
|
||||
}, reqEditorRole)
|
||||
|
||||
r.Get("/annotations", wrap(GetAnnotations))
|
||||
r.Post("/annotations/mass-delete", reqOrgAdmin, bind(dtos.DeleteAnnotationsCmd{}), wrap(DeleteAnnotations))
|
||||
|
||||
// error test
|
||||
r.Get("/metrics/error", wrap(GenerateError))
|
||||
|
||||
@@ -15,3 +15,9 @@ type Annotation struct {
|
||||
|
||||
Data *simplejson.Json `json:"data"`
|
||||
}
|
||||
|
||||
type DeleteAnnotationsCmd struct {
|
||||
AlertId int64 `json:"alertId"`
|
||||
DashboardId int64 `json:"dashboardId"`
|
||||
PanelId int64 `json:"panelId"`
|
||||
}
|
||||
|
||||
@@ -103,8 +103,10 @@ func writePIDFile() {
|
||||
|
||||
func listenToSystemSignals(server models.GrafanaServer) {
|
||||
signalChan := make(chan os.Signal, 1)
|
||||
ignoreChan := make(chan os.Signal, 1)
|
||||
code := 0
|
||||
|
||||
signal.Notify(ignoreChan, syscall.SIGHUP)
|
||||
signal.Notify(signalChan, os.Interrupt, os.Kill, syscall.SIGTERM)
|
||||
|
||||
select {
|
||||
|
||||
@@ -17,17 +17,19 @@ type SendEmailCommandSync struct {
|
||||
}
|
||||
|
||||
type SendWebhook struct {
|
||||
Url string
|
||||
User string
|
||||
Password string
|
||||
Body string
|
||||
Url string
|
||||
User string
|
||||
Password string
|
||||
Body string
|
||||
HttpMethod string
|
||||
}
|
||||
|
||||
type SendWebhookSync struct {
|
||||
Url string
|
||||
User string
|
||||
Password string
|
||||
Body string
|
||||
Url string
|
||||
User string
|
||||
Password string
|
||||
Body string
|
||||
HttpMethod string
|
||||
}
|
||||
|
||||
type SendResetPasswordEmailCommand struct {
|
||||
|
||||
@@ -24,16 +24,18 @@ func NewWebHookNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
|
||||
Url: url,
|
||||
User: model.Settings.Get("user").MustString(),
|
||||
Password: model.Settings.Get("password").MustString(),
|
||||
HttpMethod: model.Settings.Get("httpMethod").MustString("POST"),
|
||||
log: log.New("alerting.notifier.webhook"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type WebhookNotifier struct {
|
||||
NotifierBase
|
||||
Url string
|
||||
User string
|
||||
Password string
|
||||
log log.Logger
|
||||
Url string
|
||||
User string
|
||||
Password string
|
||||
HttpMethod string
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func (this *WebhookNotifier) Notify(evalContext *alerting.EvalContext) error {
|
||||
@@ -59,10 +61,11 @@ func (this *WebhookNotifier) Notify(evalContext *alerting.EvalContext) error {
|
||||
body, _ := bodyJSON.MarshalJSON()
|
||||
|
||||
cmd := &m.SendWebhookSync{
|
||||
Url: this.Url,
|
||||
User: this.User,
|
||||
Password: this.Password,
|
||||
Body: string(body),
|
||||
Url: this.Url,
|
||||
User: this.User,
|
||||
Password: this.Password,
|
||||
Body: string(body),
|
||||
HttpMethod: this.HttpMethod,
|
||||
}
|
||||
|
||||
if err := bus.DispatchCtx(evalContext.Ctx, cmd); err != nil {
|
||||
|
||||
@@ -5,6 +5,7 @@ import "github.com/grafana/grafana/pkg/components/simplejson"
|
||||
type Repository interface {
|
||||
Save(item *Item) error
|
||||
Find(query *ItemQuery) ([]*Item, error)
|
||||
Delete(params *DeleteParams) error
|
||||
}
|
||||
|
||||
type ItemQuery struct {
|
||||
@@ -20,6 +21,12 @@ type ItemQuery struct {
|
||||
Limit int64 `json:"alertId"`
|
||||
}
|
||||
|
||||
type DeleteParams struct {
|
||||
AlertId int64 `json:"alertId"`
|
||||
DashboardId int64 `json:"dashboardId"`
|
||||
PanelId int64 `json:"panelId"`
|
||||
}
|
||||
|
||||
var repositoryInstance Repository
|
||||
|
||||
func GetRepository() Repository {
|
||||
|
||||
@@ -61,19 +61,21 @@ func Init() error {
|
||||
|
||||
func SendWebhookSync(ctx context.Context, cmd *m.SendWebhookSync) error {
|
||||
return sendWebRequestSync(ctx, &Webhook{
|
||||
Url: cmd.Url,
|
||||
User: cmd.User,
|
||||
Password: cmd.Password,
|
||||
Body: cmd.Body,
|
||||
Url: cmd.Url,
|
||||
User: cmd.User,
|
||||
Password: cmd.Password,
|
||||
Body: cmd.Body,
|
||||
HttpMethod: cmd.HttpMethod,
|
||||
})
|
||||
}
|
||||
|
||||
func sendWebhook(cmd *m.SendWebhook) error {
|
||||
addToWebhookQueue(&Webhook{
|
||||
Url: cmd.Url,
|
||||
User: cmd.User,
|
||||
Password: cmd.Password,
|
||||
Body: cmd.Body,
|
||||
Url: cmd.Url,
|
||||
User: cmd.User,
|
||||
Password: cmd.Password,
|
||||
Body: cmd.Body,
|
||||
HttpMethod: cmd.HttpMethod,
|
||||
})
|
||||
|
||||
return nil
|
||||
|
||||
@@ -15,10 +15,11 @@ import (
|
||||
)
|
||||
|
||||
type Webhook struct {
|
||||
Url string
|
||||
User string
|
||||
Password string
|
||||
Body string
|
||||
Url string
|
||||
User string
|
||||
Password string
|
||||
Body string
|
||||
HttpMethod string
|
||||
}
|
||||
|
||||
var webhookQueue chan *Webhook
|
||||
@@ -44,13 +45,17 @@ func processWebhookQueue() {
|
||||
}
|
||||
|
||||
func sendWebRequestSync(ctx context.Context, webhook *Webhook) error {
|
||||
webhookLog.Debug("Sending webhook", "url", webhook.Url)
|
||||
webhookLog.Debug("Sending webhook", "url", webhook.Url, "http method", webhook.HttpMethod)
|
||||
|
||||
client := &http.Client{
|
||||
Timeout: time.Duration(10 * time.Second),
|
||||
}
|
||||
|
||||
request, err := http.NewRequest(http.MethodPost, webhook.Url, bytes.NewReader([]byte(webhook.Body)))
|
||||
if webhook.HttpMethod == "" {
|
||||
webhook.HttpMethod = http.MethodPost
|
||||
}
|
||||
|
||||
request, err := http.NewRequest(webhook.HttpMethod, webhook.Url, bytes.NewReader([]byte(webhook.Body)))
|
||||
if webhook.User != "" && webhook.Password != "" {
|
||||
request.Header.Add("Authorization", util.GetBasicAuthHeader(webhook.User, webhook.Password))
|
||||
}
|
||||
|
||||
@@ -46,13 +46,23 @@ func GetAllAlertQueryHandler(query *m.GetAllAlertsQuery) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteAlertByIdInternal(alertId int64, reason string, sess *xorm.Session) error {
|
||||
sqlog.Debug("Deleting alert", "id", alertId, "reason", reason)
|
||||
|
||||
if _, err := sess.Exec("DELETE FROM alert WHERE id = ?", alertId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := sess.Exec("DELETE FROM annotation WHERE alert_id = ?", alertId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteAlertById(cmd *m.DeleteAlertCommand) error {
|
||||
return inTransaction(func(sess *xorm.Session) error {
|
||||
if _, err := sess.Exec("DELETE FROM alert WHERE id = ?", cmd.AlertId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return deleteAlertByIdInternal(cmd.AlertId, "DeleteAlertCommand", sess)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -110,12 +120,7 @@ func DeleteAlertDefinition(dashboardId int64, sess *xorm.Session) error {
|
||||
sess.Where("dashboard_id = ?", dashboardId).Find(&alerts)
|
||||
|
||||
for _, alert := range alerts {
|
||||
_, err := sess.Exec("DELETE FROM alert WHERE id = ? ", alert.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sqlog.Debug("Alert deleted (due to dashboard deletion)", "name", alert.Name, "id", alert.Id)
|
||||
deleteAlertByIdInternal(alert.Id, "Dashboard deleted", sess)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -195,12 +200,7 @@ func deleteMissingAlerts(alerts []*m.Alert, cmd *m.SaveAlertsCommand, sess *xorm
|
||||
}
|
||||
|
||||
if missing {
|
||||
_, err := sess.Exec("DELETE FROM alert WHERE id = ?", missingAlert.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sqlog.Debug("Alert deleted", "name", missingAlert.Name, "id", missingAlert.Id)
|
||||
deleteAlertByIdInternal(missingAlert.Id, "Removed from dashboard", sess)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +248,9 @@ func PauseAlertRule(cmd *m.PauseAlertCommand) error {
|
||||
return inTransaction(func(sess *xorm.Session) error {
|
||||
alert := m.Alert{}
|
||||
|
||||
if has, err := sess.Id(cmd.AlertId).Get(&alert); err != nil {
|
||||
has, err := x.Where("id = ? AND org_id=?", cmd.AlertId, cmd.OrgId).Get(&alert)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if !has {
|
||||
return fmt.Errorf("Could not find alert")
|
||||
|
||||
@@ -84,3 +84,17 @@ func (r *SqlAnnotationRepo) Find(query *annotations.ItemQuery) ([]*annotations.I
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func (r *SqlAnnotationRepo) Delete(params *annotations.DeleteParams) error {
|
||||
return inTransaction(func(sess *xorm.Session) error {
|
||||
|
||||
sql := "DELETE FROM annotation WHERE dashboard_id = ? AND panel_id = ?"
|
||||
|
||||
_, err := sess.Exec(sql, params.DashboardId, params.PanelId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -46,5 +46,6 @@ func (s *SocialGoogle) UserInfo(client *http.Client) (*BasicUserInfo, error) {
|
||||
return &BasicUserInfo{
|
||||
Name: data.Name,
|
||||
Email: data.Email,
|
||||
Login: data.Email,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -124,10 +124,15 @@ func (e *InfluxDBExecutor) createRequest(query string) (*http.Request, error) {
|
||||
req.URL.RawQuery = params.Encode()
|
||||
|
||||
req.Header.Set("User-Agent", "Grafana")
|
||||
|
||||
if e.BasicAuth {
|
||||
req.SetBasicAuth(e.BasicAuthUser, e.BasicAuthPassword)
|
||||
}
|
||||
|
||||
if e.User != "" {
|
||||
req.SetBasicAuth(e.User, e.Password)
|
||||
}
|
||||
|
||||
glog.Debug("Influxdb request", "url", req.URL.String())
|
||||
return req, nil
|
||||
}
|
||||
|
||||
@@ -84,8 +84,10 @@ func formatLegend(metric pmodel.Metric, query *PrometheusQuery) string {
|
||||
reg, _ := regexp.Compile(`\{\{\s*(.+?)\s*\}\}`)
|
||||
|
||||
result := reg.ReplaceAllFunc([]byte(query.LegendFormat), func(in []byte) []byte {
|
||||
ind := strings.Replace(strings.Replace(string(in), "{{", "", 1), "}}", "", 1)
|
||||
if val, exists := metric[pmodel.LabelName(ind)]; exists {
|
||||
labelName := strings.Replace(string(in), "{{", "", 1)
|
||||
labelName = strings.Replace(labelName, "}}", "", 1)
|
||||
labelName = strings.TrimSpace(labelName)
|
||||
if val, exists := metric[pmodel.LabelName(labelName)]; exists {
|
||||
return []byte(val)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ func TestPrometheus(t *testing.T) {
|
||||
}
|
||||
|
||||
query := &PrometheusQuery{
|
||||
LegendFormat: "legend {{app}} {{device}} {{broken}}",
|
||||
LegendFormat: "legend {{app}} {{ device }} {{broken}}",
|
||||
}
|
||||
|
||||
So(formatLegend(metric, query), ShouldEqual, "legend backend mobile {{broken}}")
|
||||
|
||||
Reference in New Issue
Block a user