Implement initial PagerDuty notifications

This commit is contained in:
Fabian Reinartz 2015-10-19 11:45:52 +02:00
parent 6ff0cd94c5
commit aead14a99f
5 changed files with 90 additions and 17 deletions

View File

@ -143,10 +143,10 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
}
for _, pdc := range nc.PagerdutyConfigs {
if pdc.URL == "" {
if c.Global.PagerDutyURL == "" {
if c.Global.PagerdutyURL == "" {
return fmt.Errorf("no global PagerDuty URL set")
}
pdc.URL = c.Global.PagerDutyURL
pdc.URL = c.Global.PagerdutyURL
}
}
names[nc.Name] = struct{}{}
@ -161,7 +161,7 @@ var DefaultGlobalConfig = GlobalConfig{
type GlobalConfig struct {
Smarthost string `yaml:"smarthost"`
SlackURL string `yaml:"slack_url"`
PagerDutyURL string `yaml:"pagerduty_url"`
PagerdutyURL string `yaml:"pagerduty_url"`
}
func (c *GlobalConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {

View File

@ -44,8 +44,8 @@ var (
},
}
DefaultPagerDutyConfig = PagerDutyConfig{
Templates: PagerDutyTemplates{
DefaultPagerdutyConfig = PagerdutyConfig{
Templates: PagerdutyTemplates{
Description: "pagerduty.default.description",
},
}
@ -56,19 +56,19 @@ type PagerdutyConfig struct {
ServiceKey string `yaml:"service_key"`
URL string `yaml:"url"`
Templates PagerDutyTemplates `yaml:"templates"`
Templates PagerdutyTemplates `yaml:"templates"`
// Catches all undefined fields and must be empty after parsing.
XXX map[string]interface{} `yaml:",inline"`
}
type PagerDutyTemplates struct {
type PagerdutyTemplates struct {
Description string
}
// UnmarshalYAML implements the yaml.Unmarshaler interface.
func (c *PagerdutyConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
*c = DefaultPagerDutyConfig
*c = DefaultPagerdutyConfig
type plain PagerdutyConfig
if err := unmarshal((*plain)(c)); err != nil {
return err

View File

@ -51,6 +51,9 @@ func Build(confs []*config.NotificationConfig, tmpl *template.Template) map[stri
for i, c := range nc.EmailConfigs {
add(i, NewEmail(c, tmpl))
}
for i, c := range nc.PagerdutyConfigs {
add(i, NewPagerDuty(c, tmpl))
}
res[nc.Name] = fo
}
@ -210,6 +213,68 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) error {
return n.tmpl.ExecuteHTML(wc, n.conf.Templates.HTML, &data)
}
type PagerDuty struct {
conf *config.PagerdutyConfig
tmpl *template.Template
}
func NewPagerDuty(c *config.PagerdutyConfig, t *template.Template) *PagerDuty {
return &PagerDuty{conf: c, tmpl: t}
}
const (
pagerDutyEventTrigger = "trigger"
pagerDutyEventResolve = "resolve"
)
type pagerDutyMessage struct {
ServiceKey string `json:"service_key"`
EventType string `json:"event_type"`
Description string `json:"description"`
IncidentKey uint64 `json:"incident_key"`
Client string `json:"client,omitempty"`
ClientURL string `json:"client_url,omitempty"`
Details map[string]string `json:"details"`
}
func (pd *PagerDuty) Notify(ctx context.Context, as ...*types.Alert) error {
// http://developer.pagerduty.com/documentation/integration/events/trigger
alerts := types.Alerts(as...)
eventType := pagerDutyEventTrigger
if alerts.Status() == model.AlertResolved {
eventType = pagerDutyEventResolve
}
msg := &pagerDutyMessage{
ServiceKey: pd.conf.ServiceKey,
EventType: eventType,
IncidentKey: 123,
Description: "",
Details: nil,
}
if eventType == pagerDutyEventTrigger {
msg.Client = "Prometheus Alertmanager"
msg.ClientURL = ""
}
var buf bytes.Buffer
if err := json.NewEncoder(&buf).Encode(msg); err != nil {
return err
}
resp, err := ctxhttp.Post(ctx, http.DefaultClient, pd.conf.URL, contentTypeJSON, &buf)
if err != nil {
return err
}
resp.Body.Close()
if resp.StatusCode/100 != 2 {
return fmt.Errorf("unexpected status code %v", resp.StatusCode)
}
return nil
}
type Slack struct {
conf *config.SlackConfig
tmpl *template.Template

View File

@ -97,12 +97,14 @@ func NewRoute(cr *config.Route, parent *RouteOpts) *Route {
matchers = append(matchers, m)
}
return &Route{
route := &Route{
RouteOpts: opts,
Matchers: matchers,
Continue: cr.Continue,
Routes: NewRoutes(cr.Routes, &opts),
}
return route
}
func NewRoutes(croutes []*config.Route, parent *RouteOpts) Routes {

View File

@ -24,14 +24,20 @@
</span>
</div>
<div class="container-right group">
<table>
<tbody>
<tr ng-repeat="(name, val) in a.annotations | orderBy:name">
<td>{{ name }}</td>
<td>{{ val }}</td>
</tr>
</tbody>
</table>
<div class="left">
<table class="table-flat">
<tbody>
<tr ng-repeat="(name, val) in a.annotations | orderBy:name">
<td style="padding-right: 3em"><em>{{ name }}</em></td>
<td>{{ val }}</td>
</tr>
</tbody>
</table>
</div>
<div class="right">
<button type="secondary" ng-click="silence(a)" small>Silence</button>
</div>
</div>
</div>