mirror of
https://github.com/prometheus/alertmanager
synced 2025-02-20 04:37:07 +00:00
commit
42696d91de
@ -217,6 +217,17 @@ func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
ogc.APIHost += "/"
|
||||
}
|
||||
}
|
||||
for _, voc := range rcv.VictorOpsConfigs {
|
||||
if voc.APIURL == "" {
|
||||
if c.Global.VictorOpsAPIURL == "" {
|
||||
return fmt.Errorf("no global VictorOps URL set")
|
||||
}
|
||||
voc.APIURL = c.Global.VictorOpsAPIURL
|
||||
}
|
||||
if !strings.HasSuffix(voc.APIURL, "/") {
|
||||
voc.APIURL += "/"
|
||||
}
|
||||
}
|
||||
names[rcv.Name] = struct{}{}
|
||||
}
|
||||
|
||||
@ -264,6 +275,7 @@ var DefaultGlobalConfig = GlobalConfig{
|
||||
PagerdutyURL: "https://events.pagerduty.com/generic/2010-04-15/create_event.json",
|
||||
HipchatURL: "https://api.hipchat.com/",
|
||||
OpsGenieAPIHost: "https://api.opsgenie.com/",
|
||||
VictorOpsAPIURL: "https://alert.victorops.com/integrations/generic/20131114/alert/",
|
||||
}
|
||||
|
||||
// GlobalConfig defines configuration parameters that are valid globally
|
||||
@ -284,6 +296,7 @@ type GlobalConfig struct {
|
||||
HipchatURL string `yaml:"hipchat_url"`
|
||||
HipchatAuthToken Secret `yaml:"hipchat_auth_token"`
|
||||
OpsGenieAPIHost string `yaml:"opsgenie_api_host"`
|
||||
VictorOpsAPIURL string `yaml:"victorops_api_url"`
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
@ -412,6 +425,7 @@ type Receiver struct {
|
||||
WebhookConfigs []*WebhookConfig `yaml:"webhook_configs,omitempty"`
|
||||
OpsGenieConfigs []*OpsGenieConfig `yaml:"opsgenie_configs,omitempty"`
|
||||
PushoverConfigs []*PushoverConfig `yaml:"pushover_configs,omitempty"`
|
||||
VictorOpsConfigs []*VictorOpsConfig `yaml:"victorops_configs,omitempty"`
|
||||
|
||||
// Catches all undefined fields and must be empty after parsing.
|
||||
XXX map[string]interface{} `yaml:",inline"`
|
||||
|
@ -93,6 +93,16 @@ var (
|
||||
// TODO: Add a details field with all the alerts.
|
||||
}
|
||||
|
||||
// DefaultVictorOpsConfig defines default values for VictorOps configurations.
|
||||
DefaultVictorOpsConfig = VictorOpsConfig{
|
||||
NotifierConfig: NotifierConfig{
|
||||
VSendResolved: true,
|
||||
},
|
||||
MessageType: `CRITICAL`,
|
||||
StateMessage: `{{ template "victorops.default.message" . }}`,
|
||||
From: `{{ template "victorops.default.from" . }}`,
|
||||
}
|
||||
|
||||
// DefaultPushoverConfig defines default values for Pushover configurations.
|
||||
DefaultPushoverConfig = PushoverConfig{
|
||||
NotifierConfig: NotifierConfig{
|
||||
@ -309,6 +319,36 @@ func (c *OpsGenieConfig) UnmarshalYAML(unmarshal func(interface{}) error) error
|
||||
return checkOverflow(c.XXX, "opsgenie config")
|
||||
}
|
||||
|
||||
// VictorOpsConfig configures notifications via VictorOps.
|
||||
type VictorOpsConfig struct {
|
||||
NotifierConfig `yaml:",inline"`
|
||||
|
||||
APIKey Secret `yaml:"api_key"`
|
||||
APIURL string `yaml:"api_url"`
|
||||
RoutingKey string `yaml:"routing_key"`
|
||||
MessageType string `yaml:"message_type"`
|
||||
StateMessage string `yaml:"message"`
|
||||
From string `yaml:"from"`
|
||||
|
||||
XXX map[string]interface{} `yaml:",inline"`
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (c *VictorOpsConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
*c = DefaultVictorOpsConfig
|
||||
type plain VictorOpsConfig
|
||||
if err := unmarshal((*plain)(c)); err != nil {
|
||||
return err
|
||||
}
|
||||
if c.APIKey == "" {
|
||||
return fmt.Errorf("missing API key in VictorOps config")
|
||||
}
|
||||
if c.RoutingKey == "" {
|
||||
return fmt.Errorf("missing Routing key in VictorOps config")
|
||||
}
|
||||
return checkOverflow(c.XXX, "victorops config")
|
||||
}
|
||||
|
||||
type duration time.Duration
|
||||
|
||||
func (d *duration) UnmarshalText(text []byte) error {
|
||||
|
106
notify/impl.go
106
notify/impl.go
@ -136,6 +136,10 @@ func Build(confs []*config.Receiver, tmpl *template.Template) map[string]Fanout
|
||||
n := NewHipchat(c, tmpl)
|
||||
add(i, n, filter(n, c))
|
||||
}
|
||||
for i, c := range nc.VictorOpsConfigs {
|
||||
n := NewVictorOps(c, tmpl)
|
||||
add(i, n, filter(n, c))
|
||||
}
|
||||
for i, c := range nc.PushoverConfigs {
|
||||
n := NewPushover(c, tmpl)
|
||||
add(i, n, filter(n, c))
|
||||
@ -730,6 +734,108 @@ func (n *OpsGenie) Notify(ctx context.Context, as ...*types.Alert) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// VictorOps implements a Notifier for VictorOps notifications.
|
||||
type VictorOps struct {
|
||||
conf *config.VictorOpsConfig
|
||||
tmpl *template.Template
|
||||
}
|
||||
|
||||
// NewVictorOps returns a new VictorOps notifier.
|
||||
func NewVictorOps(c *config.VictorOpsConfig, t *template.Template) *VictorOps {
|
||||
return &VictorOps{
|
||||
conf: c,
|
||||
tmpl: t,
|
||||
}
|
||||
}
|
||||
|
||||
func (*VictorOps) name() string { return "victorops" }
|
||||
|
||||
const (
|
||||
victorOpsEventTrigger = "CRITICAL"
|
||||
victorOpsEventResolve = "RECOVERY"
|
||||
)
|
||||
|
||||
type victorOpsMessage struct {
|
||||
MessageType string `json:"message_type"`
|
||||
EntityID model.Fingerprint `json:"entity_id"`
|
||||
StateMessage string `json:"state_message"`
|
||||
From string `json:"monitoring_tool"`
|
||||
}
|
||||
|
||||
type victorOpsErrorResponse struct {
|
||||
Result string `json:"result"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Notify implements the Notifier interface.
|
||||
func (n *VictorOps) Notify(ctx context.Context, as ...*types.Alert) error {
|
||||
victorOpsAllowedEvents := map[string]bool{
|
||||
"INFO": true,
|
||||
"WARNING": true,
|
||||
"CRITICAL": true,
|
||||
}
|
||||
|
||||
key, ok := GroupKey(ctx)
|
||||
if !ok {
|
||||
return fmt.Errorf("group key missing")
|
||||
}
|
||||
|
||||
var err error
|
||||
var (
|
||||
alerts = types.Alerts(as...)
|
||||
data = n.tmpl.Data(receiver(ctx), groupLabels(ctx), as...)
|
||||
tmpl = tmplText(n.tmpl, data, &err)
|
||||
apiURL = fmt.Sprintf("%s%s/%s", n.conf.APIURL, n.conf.APIKey, n.conf.RoutingKey)
|
||||
messageType = n.conf.MessageType
|
||||
)
|
||||
|
||||
if alerts.Status() == model.AlertFiring && !victorOpsAllowedEvents[messageType] {
|
||||
messageType = victorOpsEventTrigger
|
||||
}
|
||||
|
||||
if alerts.Status() == model.AlertResolved {
|
||||
messageType = victorOpsEventResolve
|
||||
}
|
||||
|
||||
msg := &victorOpsMessage{
|
||||
MessageType: messageType,
|
||||
EntityID: key,
|
||||
StateMessage: tmpl(n.conf.StateMessage),
|
||||
From: tmpl(n.conf.From),
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("templating error: %s", err)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := json.NewEncoder(&buf).Encode(msg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := ctxhttp.Post(ctx, http.DefaultClient, apiURL, contentTypeJSON, &buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode/100 != 2 {
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
|
||||
var responseMessage victorOpsErrorResponse
|
||||
if err := json.Unmarshal(body, &responseMessage); err != nil {
|
||||
return fmt.Errorf("could not parse error response %q", body)
|
||||
}
|
||||
|
||||
log.With("incident", key).Debugf("unexpected VictorOps response from %s (POSTed %s), %s: %s", apiURL, msg, resp.Status, body)
|
||||
|
||||
return fmt.Errorf("error when posting alert: result %q, message %q",
|
||||
responseMessage.Result, responseMessage.Message)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pushover implements a Notifier for Pushover notifications.
|
||||
type Pushover struct {
|
||||
conf *config.PushoverConfig
|
||||
|
@ -45,6 +45,10 @@ Alerts Resolved:
|
||||
{{ define "opsgenie.default.source" }}{{ template "__alertmanagerURL" . }}{{ end }}
|
||||
|
||||
|
||||
{{ define "victorops.default.message" }}{{ template "__subject" . }} | {{ template "__alertmanagerURL" . }}{{ end }}
|
||||
{{ define "victorops.default.from" }}{{ template "__alertmanager" . }}{{ end }}
|
||||
|
||||
|
||||
{{ define "email.default.subject" }}{{ template "__subject" . }}{{ end }}
|
||||
{{ define "email.default.html" }}
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
@ -93,7 +97,7 @@ SOFTWARE.
|
||||
<tr style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 14px; margin: 0;">
|
||||
<td style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; vertical-align: top; color: #fff; font-weight: 500; text-align: center; border-radius: 3px 3px 0 0; background-color: #E6522C; margin: 0; padding: 20px;" align="center" bgcolor="#E6522C" valign="top">
|
||||
{{ .Alerts | len }} alert{{ if gt (len .Alerts) 1 }}s{{ end }} for {{ range .GroupLabels.SortedPairs }}
|
||||
{{ .Name }}={{ .Value }}
|
||||
{{ .Name }}={{ .Value }}
|
||||
{{ end }}
|
||||
</td>
|
||||
</tr>
|
||||
|
File diff suppressed because one or more lines are too long
120
ui/bindata.go
120
ui/bindata.go
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user