2017-01-11 06:57:07 -06:00
package notifiers
import (
2017-05-24 06:42:24 -05:00
"strconv"
"strings"
2017-01-11 06:57:07 -06:00
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/log"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/alerting"
)
func init ( ) {
alerting . RegisterNotifier ( & alerting . NotifierPlugin {
Type : "sensu" ,
Name : "Sensu" ,
Description : "Sends HTTP POST request to a Sensu API" ,
Factory : NewSensuNotifier ,
OptionsTemplate : `
< h3 class = "page-heading" > Sensu settings < / h3 >
< div class = "gf-form" >
< span class = "gf-form-label width-10" > Url < / span >
< input type = "text" required class = "gf-form-input max-width-26" ng - model = "ctrl.model.settings.url" placeholder = "http://sensu-api.local:4567/results" > < / input >
< / div >
2017-05-24 06:42:24 -05:00
< div class = "gf-form" >
< span class = "gf-form-label width-10" > Source < / span >
2017-06-05 07:20:34 -05:00
< input type = "text" class = "gf-form-input max-width-14" ng - model = "ctrl.model.settings.source" bs - tooltip = "'If empty rule id will be used'" data - placement = "right" > < / input >
2017-05-24 06:42:24 -05:00
< / div >
< div class = "gf-form" >
< span class = "gf-form-label width-10" > Handler < / span >
< input type = "text" class = "gf-form-input max-width-14" ng - model = "ctrl.model.settings.handler" placeholder = "default" > < / input >
< / div >
2017-01-11 06:57:07 -06:00
< div class = "gf-form" >
< span class = "gf-form-label width-10" > Username < / span >
< input type = "text" class = "gf-form-input max-width-14" ng - model = "ctrl.model.settings.username" > < / input >
< / div >
< div class = "gf-form" >
< span class = "gf-form-label width-10" > Password < / span >
< input type = "text" class = "gf-form-input max-width-14" ng - model = "ctrl.model.settings.password" > < / input >
< / div >
` ,
} )
}
func NewSensuNotifier ( model * m . AlertNotification ) ( alerting . Notifier , error ) {
url := model . Settings . Get ( "url" ) . MustString ( )
if url == "" {
return nil , alerting . ValidationError { Reason : "Could not find url property in settings" }
}
return & SensuNotifier {
NotifierBase : NewNotifierBase ( model . Id , model . IsDefault , model . Name , model . Type , model . Settings ) ,
Url : url ,
User : model . Settings . Get ( "username" ) . MustString ( ) ,
2017-05-24 06:42:24 -05:00
Source : model . Settings . Get ( "source" ) . MustString ( ) ,
2017-01-11 06:57:07 -06:00
Password : model . Settings . Get ( "password" ) . MustString ( ) ,
2017-05-24 06:42:24 -05:00
Handler : model . Settings . Get ( "handler" ) . MustString ( ) ,
2017-01-11 06:57:07 -06:00
log : log . New ( "alerting.notifier.sensu" ) ,
} , nil
}
type SensuNotifier struct {
NotifierBase
Url string
2017-05-24 06:42:24 -05:00
Source string
2017-01-11 06:57:07 -06:00
User string
Password string
2017-05-24 06:42:24 -05:00
Handler string
2017-01-11 06:57:07 -06:00
log log . Logger
}
2017-11-15 10:53:02 -06:00
func ( this * SensuNotifier ) ShouldNotify ( context * alerting . EvalContext ) bool {
return defaultShouldNotify ( context )
}
2017-01-11 06:57:07 -06:00
func ( this * SensuNotifier ) Notify ( evalContext * alerting . EvalContext ) error {
this . log . Info ( "Sending sensu result" )
bodyJSON := simplejson . New ( )
bodyJSON . Set ( "ruleId" , evalContext . Rule . Id )
// Sensu alerts cannot have spaces in them
bodyJSON . Set ( "name" , strings . Replace ( evalContext . Rule . Name , " " , "_" , - 1 ) )
2017-05-24 06:42:24 -05:00
// Sensu alerts require a source. We set it to the user-specified value (optional),
// else we fallback and use the grafana ruleID.
if this . Source != "" {
bodyJSON . Set ( "source" , this . Source )
} else {
bodyJSON . Set ( "source" , "grafana_rule_" + strconv . FormatInt ( evalContext . Rule . Id , 10 ) )
}
2017-01-11 06:57:07 -06:00
// Finally, sensu expects an output
// We set it to a default output
bodyJSON . Set ( "output" , "Grafana Metric Condition Met" )
bodyJSON . Set ( "evalMatches" , evalContext . EvalMatches )
if evalContext . Rule . State == "alerting" {
bodyJSON . Set ( "status" , 2 )
} else if evalContext . Rule . State == "no_data" {
bodyJSON . Set ( "status" , 1 )
} else {
bodyJSON . Set ( "status" , 0 )
}
2017-05-24 06:42:24 -05:00
if this . Handler != "" {
bodyJSON . Set ( "handler" , this . Handler )
}
2017-01-11 06:57:07 -06:00
ruleUrl , err := evalContext . GetRuleUrl ( )
if err == nil {
bodyJSON . Set ( "ruleUrl" , ruleUrl )
}
if evalContext . ImagePublicUrl != "" {
bodyJSON . Set ( "imageUrl" , evalContext . ImagePublicUrl )
}
if evalContext . Rule . Message != "" {
2017-10-17 16:22:56 -05:00
bodyJSON . Set ( "output" , evalContext . Rule . Message )
2017-01-11 06:57:07 -06:00
}
body , _ := bodyJSON . MarshalJSON ( )
cmd := & m . SendWebhookSync {
Url : this . Url ,
User : this . User ,
Password : this . Password ,
Body : string ( body ) ,
HttpMethod : "POST" ,
}
if err := bus . DispatchCtx ( evalContext . Ctx , cmd ) ; err != nil {
this . log . Error ( "Failed to send sensu event" , "error" , err , "sensu" , this . Name )
return err
}
return nil
}