mirror of
https://github.com/grafana/grafana.git
synced 2024-11-22 08:56:43 -06:00
NGAlert: Send list of available ngalert notification channels via API (#33489)
Signed-off-by: Ganesh Vernekar <ganeshvern@gmail.com>
This commit is contained in:
parent
ab872612ce
commit
918552d34b
@ -11,6 +11,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/alerting"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier"
|
||||
"github.com/grafana/grafana/pkg/services/search"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
@ -179,8 +180,15 @@ func GetAlert(c *models.ReqContext) response.Response {
|
||||
return response.JSON(200, &query.Result)
|
||||
}
|
||||
|
||||
func GetAlertNotifiers(c *models.ReqContext) response.Response {
|
||||
return response.JSON(200, alerting.GetNotifiers())
|
||||
func GetAlertNotifiers(ngalertEnabled bool) func(*models.ReqContext) response.Response {
|
||||
return func(_ *models.ReqContext) response.Response {
|
||||
if ngalertEnabled {
|
||||
return response.JSON(200, notifier.GetAvailableNotifiers())
|
||||
}
|
||||
// TODO(codesome): This wont be required in 8.0 since ngalert
|
||||
// will be enabled by default with no disabling. This is to be removed later.
|
||||
return response.JSON(200, alerting.GetNotifiers())
|
||||
}
|
||||
}
|
||||
|
||||
func GetAlertNotificationLookup(c *models.ReqContext) response.Response {
|
||||
|
@ -379,7 +379,9 @@ func (hs *HTTPServer) registerRoutes() {
|
||||
alertsRoute.Get("/states-for-dashboard", routing.Wrap(GetAlertStatesForDashboard))
|
||||
})
|
||||
|
||||
apiRoute.Get("/alert-notifiers", reqEditorRole, routing.Wrap(GetAlertNotifiers))
|
||||
apiRoute.Get("/alert-notifiers", reqEditorRole, routing.Wrap(
|
||||
GetAlertNotifiers(hs.Alertmanager != nil && !hs.Alertmanager.IsDisabled())),
|
||||
)
|
||||
|
||||
apiRoute.Group("/alert-notifications", func(alertNotifications routing.RouteRegister) {
|
||||
alertNotifications.Get("/", routing.Wrap(GetAlertNotifications))
|
||||
|
@ -38,6 +38,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/live"
|
||||
"github.com/grafana/grafana/pkg/services/live/pushhttp"
|
||||
"github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/notifier"
|
||||
"github.com/grafana/grafana/pkg/services/provisioning"
|
||||
"github.com/grafana/grafana/pkg/services/quota"
|
||||
"github.com/grafana/grafana/pkg/services/rendering"
|
||||
@ -100,6 +101,7 @@ type HTTPServer struct {
|
||||
PluginDashboardService *plugindashboards.Service `inject:""`
|
||||
AlertEngine *alerting.AlertEngine `inject:""`
|
||||
LoadSchemaService *schemaloader.SchemaLoaderService `inject:""`
|
||||
Alertmanager *notifier.Alertmanager `inject:""`
|
||||
Listener net.Listener
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ type InputType string
|
||||
const (
|
||||
// InputTypeText will render a text field in the frontend
|
||||
InputTypeText = "text"
|
||||
// InputTypePassword will render a text field in the frontend
|
||||
// InputTypePassword will render a password field in the frontend
|
||||
InputTypePassword = "password"
|
||||
)
|
||||
|
||||
|
@ -28,7 +28,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/registry"
|
||||
"github.com/grafana/grafana/pkg/services/alerting"
|
||||
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/metrics"
|
||||
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
@ -543,29 +542,3 @@ func timeoutFunc(d time.Duration) time.Duration {
|
||||
}
|
||||
return d + waitFunc()
|
||||
}
|
||||
|
||||
// GetAvailableNotifiers returns the metadata of all the notification channels that can be configured.
|
||||
func (am *Alertmanager) GetAvailableNotifiers() []*alerting.NotifierPlugin {
|
||||
return []*alerting.NotifierPlugin{
|
||||
{
|
||||
Type: "email",
|
||||
Name: "Email",
|
||||
Description: "Sends notifications using Grafana server configured SMTP settings",
|
||||
Heading: "Email settings",
|
||||
Options: []alerting.NotifierOption{
|
||||
{
|
||||
Label: "Single email",
|
||||
Description: "Send a single email to all recipients",
|
||||
Element: alerting.ElementTypeCheckbox,
|
||||
PropertyName: "singleEmail",
|
||||
}, {
|
||||
Label: "Addresses",
|
||||
Description: "You can enter multiple email addresses using a \";\" separator",
|
||||
Element: alerting.ElementTypeTextArea,
|
||||
PropertyName: "addresses",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
344
pkg/services/ngalert/notifier/available_channels.go
Normal file
344
pkg/services/ngalert/notifier/available_channels.go
Normal file
@ -0,0 +1,344 @@
|
||||
package notifier
|
||||
|
||||
import "github.com/grafana/grafana/pkg/services/alerting"
|
||||
|
||||
// GetAvailableNotifiers returns the metadata of all the notification channels that can be configured.
|
||||
func GetAvailableNotifiers() []*alerting.NotifierPlugin {
|
||||
return []*alerting.NotifierPlugin{
|
||||
{
|
||||
Type: "dingding",
|
||||
Name: "DingDing",
|
||||
Description: "Sends HTTP POST request to DingDing",
|
||||
Heading: "DingDing settings",
|
||||
Options: []alerting.NotifierOption{
|
||||
{
|
||||
Label: "Url",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Placeholder: "https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxx",
|
||||
PropertyName: "url",
|
||||
Required: true,
|
||||
},
|
||||
{
|
||||
Label: "Message Type",
|
||||
Element: alerting.ElementTypeSelect,
|
||||
PropertyName: "msgType",
|
||||
SelectOptions: []alerting.SelectOption{
|
||||
{
|
||||
Value: "link",
|
||||
Label: "Link"},
|
||||
{
|
||||
Value: "actionCard",
|
||||
Label: "ActionCard",
|
||||
},
|
||||
},
|
||||
},
|
||||
{ // New in 8.0.
|
||||
Label: "Message",
|
||||
Element: alerting.ElementTypeTextArea,
|
||||
Placeholder: `{{ template "default.message" . }}`,
|
||||
PropertyName: "message",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "email",
|
||||
Name: "Email",
|
||||
Description: "Sends notifications using Grafana server configured SMTP settings",
|
||||
Heading: "Email settings",
|
||||
Options: []alerting.NotifierOption{
|
||||
{
|
||||
Label: "Single email",
|
||||
Description: "Send a single email to all recipients",
|
||||
Element: alerting.ElementTypeCheckbox,
|
||||
PropertyName: "singleEmail",
|
||||
},
|
||||
{
|
||||
Label: "Addresses",
|
||||
Description: "You can enter multiple email addresses using a \";\" separator",
|
||||
Element: alerting.ElementTypeTextArea,
|
||||
PropertyName: "addresses",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "pagerduty",
|
||||
Name: "PagerDuty",
|
||||
Description: "Sends notifications to PagerDuty",
|
||||
Heading: "PagerDuty settings",
|
||||
Options: []alerting.NotifierOption{
|
||||
{
|
||||
Label: "Integration Key",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Placeholder: "Pagerduty Integration Key",
|
||||
PropertyName: "integrationKey",
|
||||
Required: true,
|
||||
Secure: true,
|
||||
},
|
||||
{
|
||||
Label: "Severity",
|
||||
Element: alerting.ElementTypeSelect,
|
||||
SelectOptions: []alerting.SelectOption{
|
||||
{
|
||||
Value: "critical",
|
||||
Label: "Critical",
|
||||
},
|
||||
{
|
||||
Value: "error",
|
||||
Label: "Error",
|
||||
},
|
||||
{
|
||||
Value: "warning",
|
||||
Label: "Warning",
|
||||
},
|
||||
{
|
||||
Value: "info",
|
||||
Label: "Info",
|
||||
},
|
||||
},
|
||||
PropertyName: "severity",
|
||||
},
|
||||
{ // New in 8.0.
|
||||
Label: "Class",
|
||||
Description: "The class/type of the event, for example 'ping failure' or 'cpu load'",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
PropertyName: "class",
|
||||
},
|
||||
{ // New in 8.0.
|
||||
Label: "Component",
|
||||
Description: "Component of the source machine that is responsible for the event, for example mysql or eth0",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Placeholder: "Grafana",
|
||||
PropertyName: "component",
|
||||
},
|
||||
{ // New in 8.0.
|
||||
Label: "Group",
|
||||
Description: "Logical grouping of components of a service, for example 'app-stack'",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
PropertyName: "group",
|
||||
},
|
||||
{ // New in 8.0.
|
||||
Label: "Summary",
|
||||
Description: "You can use templates for summary",
|
||||
Element: alerting.ElementTypeTextArea,
|
||||
Placeholder: `{{ template "default.message" . }}`,
|
||||
PropertyName: "summary",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "slack",
|
||||
Name: "Slack",
|
||||
Description: "Sends notifications to Slack",
|
||||
Heading: "Slack settings",
|
||||
Options: []alerting.NotifierOption{
|
||||
{
|
||||
Label: "Recipient",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Description: "Specify channel or user, use #channel-name, @username (has to be all lowercase, no whitespace), or user/channel Slack ID - required unless you provide a webhook",
|
||||
PropertyName: "recipient",
|
||||
},
|
||||
// Logically, this field should be required when not using a webhook, since the Slack API needs a token.
|
||||
// However, since the UI doesn't allow to say that a field is required or not depending on another field,
|
||||
// we've gone with the compromise of making this field optional and instead return a validation error
|
||||
// if it's necessary and missing.
|
||||
{
|
||||
Label: "Token",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Description: "Provide a Slack API token (starts with \"xoxb\") - required unless you provide a webhook",
|
||||
PropertyName: "token",
|
||||
Secure: true,
|
||||
},
|
||||
{
|
||||
Label: "Username",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Description: "Set the username for the bot's message",
|
||||
PropertyName: "username",
|
||||
},
|
||||
{
|
||||
Label: "Icon emoji",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Description: "Provide an emoji to use as the icon for the bot's message. Overrides the icon URL.",
|
||||
PropertyName: "icon_emoji",
|
||||
},
|
||||
{
|
||||
Label: "Icon URL",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Description: "Provide a URL to an image to use as the icon for the bot's message",
|
||||
PropertyName: "icon_url",
|
||||
},
|
||||
{
|
||||
Label: "Mention Users",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Description: "Mention one or more users (comma separated) when notifying in a channel, by ID (you can copy this from the user's Slack profile)",
|
||||
PropertyName: "mentionUsers",
|
||||
},
|
||||
{
|
||||
Label: "Mention Groups",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Description: "Mention one or more groups (comma separated) when notifying in a channel (you can copy this from the group's Slack profile URL)",
|
||||
PropertyName: "mentionGroups",
|
||||
},
|
||||
{
|
||||
Label: "Mention Channel",
|
||||
Element: alerting.ElementTypeSelect,
|
||||
SelectOptions: []alerting.SelectOption{
|
||||
{
|
||||
Value: "",
|
||||
Label: "Disabled",
|
||||
},
|
||||
{
|
||||
Value: "here",
|
||||
Label: "Every active channel member",
|
||||
},
|
||||
{
|
||||
Value: "channel",
|
||||
Label: "Every channel member",
|
||||
},
|
||||
},
|
||||
Description: "Mention whole channel or just active members when notifying",
|
||||
PropertyName: "mentionChannel",
|
||||
},
|
||||
{
|
||||
Label: "Webhook URL",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Description: "Optionally provide a Slack incoming webhook URL for sending messages, in this case the token isn't necessary",
|
||||
Placeholder: "Slack incoming webhook URL",
|
||||
PropertyName: "url",
|
||||
Secure: true,
|
||||
},
|
||||
{ // New in 8.0.
|
||||
Label: "Title",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Description: "Templated title of the slack message",
|
||||
PropertyName: "title",
|
||||
Placeholder: `{{ template "slack.default.title" . }}`,
|
||||
},
|
||||
{ // New in 8.0.
|
||||
Label: "Text Body",
|
||||
Element: alerting.ElementTypeTextArea,
|
||||
Description: "Body of the slack message",
|
||||
PropertyName: "text",
|
||||
Placeholder: `{{ template "slack.default.text" . }}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "teams",
|
||||
Name: "Microsoft Teams",
|
||||
Description: "Sends notifications using Incoming Webhook connector to Microsoft Teams",
|
||||
Heading: "Teams settings",
|
||||
Options: []alerting.NotifierOption{
|
||||
{
|
||||
Label: "URL",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Placeholder: "Teams incoming webhook url",
|
||||
PropertyName: "url",
|
||||
Required: true,
|
||||
},
|
||||
{ // New in 8.0.
|
||||
Label: "Message",
|
||||
Element: alerting.ElementTypeTextArea,
|
||||
Placeholder: `{{ template "default.message" . }}`,
|
||||
PropertyName: "message",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "telegram",
|
||||
Name: "Telegram",
|
||||
Description: "Sends notifications to Telegram",
|
||||
Heading: "Telegram API settings",
|
||||
Options: []alerting.NotifierOption{
|
||||
{
|
||||
Label: "BOT API Token",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Placeholder: "Telegram BOT API Token",
|
||||
PropertyName: "bottoken",
|
||||
Required: true,
|
||||
Secure: true,
|
||||
},
|
||||
{
|
||||
Label: "Chat ID",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
Description: "Integer Telegram Chat Identifier",
|
||||
PropertyName: "chatid",
|
||||
Required: true,
|
||||
},
|
||||
{ // New in 8.0.
|
||||
Label: "Message",
|
||||
Element: alerting.ElementTypeTextArea,
|
||||
Placeholder: `{{ template "default.message" . }}`,
|
||||
PropertyName: "message",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Type: "webhook",
|
||||
Name: "webhook",
|
||||
Description: "Sends HTTP POST request to a URL",
|
||||
Heading: "Webhook settings",
|
||||
Options: []alerting.NotifierOption{
|
||||
{
|
||||
Label: "Url",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
PropertyName: "url",
|
||||
Required: true,
|
||||
},
|
||||
{
|
||||
Label: "Http Method",
|
||||
Element: alerting.ElementTypeSelect,
|
||||
SelectOptions: []alerting.SelectOption{
|
||||
{
|
||||
Value: "POST",
|
||||
Label: "POST",
|
||||
},
|
||||
{
|
||||
Value: "PUT",
|
||||
Label: "PUT",
|
||||
},
|
||||
},
|
||||
PropertyName: "httpMethod",
|
||||
},
|
||||
{
|
||||
Label: "Username",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
PropertyName: "username",
|
||||
},
|
||||
{
|
||||
Label: "Password",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypePassword,
|
||||
PropertyName: "password",
|
||||
Secure: true,
|
||||
},
|
||||
{ // New in 8.0. TODO: How to enforce only numbers?
|
||||
Label: "Max Alerts",
|
||||
Description: "Max alerts to include in a notification. Remaining alerts in the same batch will be ignored above this number. 0 means no limit.",
|
||||
Element: alerting.ElementTypeInput,
|
||||
InputType: alerting.InputTypeText,
|
||||
PropertyName: "maxAlerts",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
@ -54,31 +54,22 @@ func NewPagerdutyNotifier(model *models.AlertNotification, t *template.Template)
|
||||
return nil, alerting.ValidationError{Reason: "Could not find integration key property in settings"}
|
||||
}
|
||||
|
||||
customDetails := model.Settings.Get("customDetails").MustMap(map[string]interface{}{
|
||||
"firing": `{{ template "pagerduty.default.instances" .Alerts.Firing }}`,
|
||||
"resolved": `{{ template "pagerduty.default.instances" .Alerts.Resolved }}`,
|
||||
"num_firing": `{{ .Alerts.Firing | len }}`,
|
||||
"num_resolved": `{{ .Alerts.Resolved | len }}`,
|
||||
})
|
||||
|
||||
details := make(map[string]string, len(customDetails))
|
||||
for k, v := range customDetails {
|
||||
if val, ok := v.(string); ok {
|
||||
details[k] = val
|
||||
}
|
||||
}
|
||||
|
||||
return &PagerdutyNotifier{
|
||||
NotifierBase: old_notifiers.NewNotifierBase(model),
|
||||
Key: key,
|
||||
CustomDetails: details,
|
||||
Severity: model.Settings.Get("severity").MustString("critical"),
|
||||
Class: model.Settings.Get("class").MustString("todo_class"), // TODO
|
||||
Component: model.Settings.Get("component").MustString("Grafana"),
|
||||
Group: model.Settings.Get("group").MustString("todo_group"), // TODO
|
||||
Summary: model.Settings.Get("summary").MustString(`{{ template "pagerduty.default.description" .}}`),
|
||||
tmpl: t,
|
||||
log: log.New("alerting.notifier." + model.Name),
|
||||
NotifierBase: old_notifiers.NewNotifierBase(model),
|
||||
Key: key,
|
||||
CustomDetails: map[string]string{
|
||||
"firing": `{{ template "pagerduty.default.instances" .Alerts.Firing }}`,
|
||||
"resolved": `{{ template "pagerduty.default.instances" .Alerts.Resolved }}`,
|
||||
"num_firing": `{{ .Alerts.Firing | len }}`,
|
||||
"num_resolved": `{{ .Alerts.Resolved | len }}`,
|
||||
},
|
||||
Severity: model.Settings.Get("severity").MustString("critical"),
|
||||
Class: model.Settings.Get("class").MustString("default"),
|
||||
Component: model.Settings.Get("component").MustString("Grafana"),
|
||||
Group: model.Settings.Get("group").MustString("default"),
|
||||
Summary: model.Settings.Get("summary").MustString(`{{ template "pagerduty.default.description" .}}`),
|
||||
tmpl: t,
|
||||
log: log.New("alerting.notifier." + model.Name),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -161,6 +152,11 @@ func (pn *PagerdutyNotifier) buildPagerdutyMessage(ctx context.Context, alerts m
|
||||
},
|
||||
}
|
||||
|
||||
if len(msg.Payload.Summary) > 1024 {
|
||||
// This is the Pagerduty limit.
|
||||
msg.Payload.Summary = msg.Payload.Summary[:1021] + "..."
|
||||
}
|
||||
|
||||
if hostname, err := os.Hostname(); err == nil {
|
||||
// TODO: should this be configured like in Prometheus AM?
|
||||
msg.Payload.Source = hostname
|
||||
|
@ -59,9 +59,9 @@ func TestPagerdutyNotifier(t *testing.T) {
|
||||
Summary: "[FIRING:1] (val1)",
|
||||
Source: hostname,
|
||||
Severity: "critical",
|
||||
Class: "todo_class",
|
||||
Class: "default",
|
||||
Component: "Grafana",
|
||||
Group: "todo_group",
|
||||
Group: "default",
|
||||
CustomDetails: map[string]string{
|
||||
"firing": "Labels:\n - alertname = alert1\n - lbl1 = val1\nAnnotations:\n - ann1 = annv1\nSource: \n",
|
||||
"num_firing": "1",
|
||||
|
@ -41,7 +41,6 @@ type SlackNotifier struct {
|
||||
Recipient string
|
||||
Text string
|
||||
Title string
|
||||
Fallback string
|
||||
MentionUsers []string
|
||||
MentionGroups []string
|
||||
MentionChannel string
|
||||
@ -123,7 +122,6 @@ func NewSlackNotifier(model *models.AlertNotification, t *template.Template) (*S
|
||||
Token: token,
|
||||
Text: model.Settings.Get("text").MustString(`{{ template "slack.default.text" . }}`),
|
||||
Title: model.Settings.Get("title").MustString(`{{ template "slack.default.title" . }}`),
|
||||
Fallback: model.Settings.Get("fallback").MustString(`{{ template "slack.default.title" . }}`),
|
||||
log: log.New("alerting.notifier.slack"),
|
||||
tmpl: t,
|
||||
}, nil
|
||||
@ -254,7 +252,7 @@ func (sn *SlackNotifier) buildSlackMessage(ctx context.Context, as []*types.Aler
|
||||
{
|
||||
Color: getAlertStatusColor(alerts.Status()),
|
||||
Title: tmpl(sn.Title),
|
||||
Fallback: tmpl(sn.Fallback),
|
||||
Fallback: tmpl(sn.Title),
|
||||
Footer: "Grafana v" + setting.BuildVersion,
|
||||
FooterIcon: FooterIconURL,
|
||||
Ts: time.Now().Unix(),
|
||||
|
@ -140,7 +140,7 @@ func TestSlackNotifier(t *testing.T) {
|
||||
Title: "2 firing, 0 resolved",
|
||||
TitleLink: "TODO: rule URL",
|
||||
Text: "",
|
||||
Fallback: "[FIRING:2] ",
|
||||
Fallback: "2 firing, 0 resolved",
|
||||
Fields: nil,
|
||||
Footer: "Grafana v",
|
||||
FooterIcon: "https://grafana.com/assets/img/fav32.png",
|
||||
|
664
pkg/tests/api/alerting/api_available_channel_test.go
Normal file
664
pkg/tests/api/alerting/api_available_channel_test.go
Normal file
@ -0,0 +1,664 @@
|
||||
package alerting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/tests/testinfra"
|
||||
)
|
||||
|
||||
func TestAvailableChannels(t *testing.T) {
|
||||
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
||||
EnableFeatureToggles: []string{"ngalert"},
|
||||
AnonymousUserRole: models.ROLE_EDITOR,
|
||||
})
|
||||
|
||||
store := testinfra.SetUpDatabase(t, dir)
|
||||
grafanaListedAddr := testinfra.StartGrafana(t, dir, path, store)
|
||||
|
||||
alertsURL := fmt.Sprintf("http://%s/api/alert-notifiers", grafanaListedAddr)
|
||||
// nolint:gosec
|
||||
resp, err := http.Get(alertsURL)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
err := resp.Body.Close()
|
||||
require.NoError(t, err)
|
||||
})
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 200, resp.StatusCode)
|
||||
require.JSONEq(t, expAvailableChannelJsonOutput, string(b))
|
||||
}
|
||||
|
||||
var expAvailableChannelJsonOutput = `
|
||||
[
|
||||
{
|
||||
"type": "dingding",
|
||||
"name": "DingDing",
|
||||
"heading": "DingDing settings",
|
||||
"description": "Sends HTTP POST request to DingDing",
|
||||
"info": "",
|
||||
"options": [
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Url",
|
||||
"description": "",
|
||||
"placeholder": "https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxx",
|
||||
"propertyName": "url",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": true,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "select",
|
||||
"inputType": "",
|
||||
"label": "Message Type",
|
||||
"description": "",
|
||||
"placeholder": "",
|
||||
"propertyName": "msgType",
|
||||
"selectOptions": [
|
||||
{
|
||||
"value": "link",
|
||||
"label": "Link"
|
||||
},
|
||||
{
|
||||
"value": "actionCard",
|
||||
"label": "ActionCard"
|
||||
}
|
||||
],
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "textarea",
|
||||
"inputType": "",
|
||||
"label": "Message",
|
||||
"description": "",
|
||||
"placeholder": "{{ template \"default.message\" . }}",
|
||||
"propertyName": "message",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "email",
|
||||
"name": "Email",
|
||||
"heading": "Email settings",
|
||||
"description": "Sends notifications using Grafana server configured SMTP settings",
|
||||
"info": "",
|
||||
"options": [
|
||||
{
|
||||
"element": "checkbox",
|
||||
"inputType": "",
|
||||
"label": "Single email",
|
||||
"description": "Send a single email to all recipients",
|
||||
"placeholder": "",
|
||||
"propertyName": "singleEmail",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "textarea",
|
||||
"inputType": "",
|
||||
"label": "Addresses",
|
||||
"description": "You can enter multiple email addresses using a \";\" separator",
|
||||
"placeholder": "",
|
||||
"propertyName": "addresses",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": true,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "pagerduty",
|
||||
"name": "PagerDuty",
|
||||
"heading": "PagerDuty settings",
|
||||
"description": "Sends notifications to PagerDuty",
|
||||
"info": "",
|
||||
"options": [
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Integration Key",
|
||||
"description": "",
|
||||
"placeholder": "Pagerduty Integration Key",
|
||||
"propertyName": "integrationKey",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": true,
|
||||
"validationRule": "",
|
||||
"secure": true
|
||||
},
|
||||
{
|
||||
"element": "select",
|
||||
"inputType": "",
|
||||
"label": "Severity",
|
||||
"description": "",
|
||||
"placeholder": "",
|
||||
"propertyName": "severity",
|
||||
"selectOptions": [
|
||||
{
|
||||
"value": "critical",
|
||||
"label": "Critical"
|
||||
},
|
||||
{
|
||||
"value": "error",
|
||||
"label": "Error"
|
||||
},
|
||||
{
|
||||
"value": "warning",
|
||||
"label": "Warning"
|
||||
},
|
||||
{
|
||||
"value": "info",
|
||||
"label": "Info"
|
||||
}
|
||||
],
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Class",
|
||||
"description": "The class/type of the event, for example 'ping failure' or 'cpu load'",
|
||||
"placeholder": "",
|
||||
"propertyName": "class",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Component",
|
||||
"description": "Component of the source machine that is responsible for the event, for example mysql or eth0",
|
||||
"placeholder": "Grafana",
|
||||
"propertyName": "component",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Group",
|
||||
"description": "Logical grouping of components of a service, for example 'app-stack'",
|
||||
"placeholder": "",
|
||||
"propertyName": "group",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "textarea",
|
||||
"inputType": "",
|
||||
"label": "Summary",
|
||||
"description": "You can use templates for summary",
|
||||
"placeholder": "{{ template \"default.message\" . }}",
|
||||
"propertyName": "summary",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "slack",
|
||||
"name": "Slack",
|
||||
"heading": "Slack settings",
|
||||
"description": "Sends notifications to Slack",
|
||||
"info": "",
|
||||
"options": [
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Recipient",
|
||||
"description": "Specify channel or user, use #channel-name, @username (has to be all lowercase, no whitespace), or user/channel Slack ID - required unless you provide a webhook",
|
||||
"placeholder": "",
|
||||
"propertyName": "recipient",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Token",
|
||||
"description": "Provide a Slack API token (starts with \"xoxb\") - required unless you provide a webhook",
|
||||
"placeholder": "",
|
||||
"propertyName": "token",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": true
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Username",
|
||||
"description": "Set the username for the bot's message",
|
||||
"placeholder": "",
|
||||
"propertyName": "username",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Icon emoji",
|
||||
"description": "Provide an emoji to use as the icon for the bot's message. Overrides the icon URL.",
|
||||
"placeholder": "",
|
||||
"propertyName": "icon_emoji",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Icon URL",
|
||||
"description": "Provide a URL to an image to use as the icon for the bot's message",
|
||||
"placeholder": "",
|
||||
"propertyName": "icon_url",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Mention Users",
|
||||
"description": "Mention one or more users (comma separated) when notifying in a channel, by ID (you can copy this from the user's Slack profile)",
|
||||
"placeholder": "",
|
||||
"propertyName": "mentionUsers",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Mention Groups",
|
||||
"description": "Mention one or more groups (comma separated) when notifying in a channel (you can copy this from the group's Slack profile URL)",
|
||||
"placeholder": "",
|
||||
"propertyName": "mentionGroups",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "select",
|
||||
"inputType": "",
|
||||
"label": "Mention Channel",
|
||||
"description": "Mention whole channel or just active members when notifying",
|
||||
"placeholder": "",
|
||||
"propertyName": "mentionChannel",
|
||||
"selectOptions": [
|
||||
{
|
||||
"value": "",
|
||||
"label": "Disabled"
|
||||
},
|
||||
{
|
||||
"value": "here",
|
||||
"label": "Every active channel member"
|
||||
},
|
||||
{
|
||||
"value": "channel",
|
||||
"label": "Every channel member"
|
||||
}
|
||||
],
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Webhook URL",
|
||||
"description": "Optionally provide a Slack incoming webhook URL for sending messages, in this case the token isn't necessary",
|
||||
"placeholder": "Slack incoming webhook URL",
|
||||
"propertyName": "url",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": true
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Title",
|
||||
"description": "Templated title of the slack message",
|
||||
"placeholder": "{{ template \"slack.default.title\" . }}",
|
||||
"propertyName": "title",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "textarea",
|
||||
"inputType": "",
|
||||
"label": "Text Body",
|
||||
"description": "Body of the slack message",
|
||||
"placeholder": "{{ template \"slack.default.text\" . }}",
|
||||
"propertyName": "text",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "teams",
|
||||
"name": "Microsoft Teams",
|
||||
"heading": "Teams settings",
|
||||
"description": "Sends notifications using Incoming Webhook connector to Microsoft Teams",
|
||||
"info": "",
|
||||
"options": [
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "URL",
|
||||
"description": "",
|
||||
"placeholder": "Teams incoming webhook url",
|
||||
"propertyName": "url",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": true,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "textarea",
|
||||
"inputType": "",
|
||||
"label": "Message",
|
||||
"description": "",
|
||||
"placeholder": "{{ template \"default.message\" . }}",
|
||||
"propertyName": "message",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "telegram",
|
||||
"name": "Telegram",
|
||||
"heading": "Telegram API settings",
|
||||
"description": "Sends notifications to Telegram",
|
||||
"info": "",
|
||||
"options": [
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "BOT API Token",
|
||||
"description": "",
|
||||
"placeholder": "Telegram BOT API Token",
|
||||
"propertyName": "bottoken",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": true,
|
||||
"validationRule": "",
|
||||
"secure": true
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Chat ID",
|
||||
"description": "Integer Telegram Chat Identifier",
|
||||
"placeholder": "",
|
||||
"propertyName": "chatid",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": true,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "textarea",
|
||||
"inputType": "",
|
||||
"label": "Message",
|
||||
"description": "",
|
||||
"placeholder": "{{ template \"default.message\" . }}",
|
||||
"propertyName": "message",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "webhook",
|
||||
"name": "webhook",
|
||||
"heading": "Webhook settings",
|
||||
"description": "Sends HTTP POST request to a URL",
|
||||
"info": "",
|
||||
"options": [
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Url",
|
||||
"description": "",
|
||||
"placeholder": "",
|
||||
"propertyName": "url",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": true,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "select",
|
||||
"inputType": "",
|
||||
"label": "Http Method",
|
||||
"description": "",
|
||||
"placeholder": "",
|
||||
"propertyName": "httpMethod",
|
||||
"selectOptions": [
|
||||
{
|
||||
"value": "POST",
|
||||
"label": "POST"
|
||||
},
|
||||
{
|
||||
"value": "PUT",
|
||||
"label": "PUT"
|
||||
}
|
||||
],
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Username",
|
||||
"description": "",
|
||||
"placeholder": "",
|
||||
"propertyName": "username",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "password",
|
||||
"label": "Password",
|
||||
"description": "",
|
||||
"placeholder": "",
|
||||
"propertyName": "password",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": true
|
||||
},
|
||||
{
|
||||
"element": "input",
|
||||
"inputType": "text",
|
||||
"label": "Max Alerts",
|
||||
"description": "Max alerts to include in a notification. Remaining alerts in the same batch will be ignored above this number. 0 means no limit.",
|
||||
"placeholder": "",
|
||||
"propertyName": "maxAlerts",
|
||||
"selectOptions": null,
|
||||
"showWhen": {
|
||||
"field": "",
|
||||
"is": ""
|
||||
},
|
||||
"required": false,
|
||||
"validationRule": "",
|
||||
"secure": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
`
|
Loading…
Reference in New Issue
Block a user