diff --git a/pkg/api/alerting.go b/pkg/api/alerting.go
index 7b48a70dcf4..143c72106fe 100644
--- a/pkg/api/alerting.go
+++ b/pkg/api/alerting.go
@@ -172,6 +172,10 @@ func DelAlert(c *middleware.Context) Response {
return Json(200, resp)
}
+func GetAlertNotifiers(c *middleware.Context) Response {
+ return Json(200, alerting.GetNotifiers())
+}
+
func GetAlertNotifications(c *middleware.Context) Response {
query := &models.GetAllAlertNotificationsQuery{OrgId: c.OrgId}
diff --git a/pkg/api/api.go b/pkg/api/api.go
index e931c5de601..ef550838c56 100644
--- a/pkg/api/api.go
+++ b/pkg/api/api.go
@@ -262,6 +262,7 @@ func Register(r *macaron.Macaron) {
})
r.Get("/alert-notifications", wrap(GetAlertNotifications))
+ r.Get("/alert-notifiers", wrap(GetAlertNotifiers))
r.Group("/alert-notifications", func() {
r.Post("/test", bind(dtos.NotificationTestCommand{}), wrap(NotificationTest))
diff --git a/pkg/api/index.go b/pkg/api/index.go
index 5bc4344a8ba..715baefae78 100644
--- a/pkg/api/index.go
+++ b/pkg/api/index.go
@@ -106,7 +106,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
if c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR {
alertChildNavs := []*dtos.NavLink{
{Text: "Alert List", Url: setting.AppSubUrl + "/alerting/list"},
- {Text: "Notifications", Url: setting.AppSubUrl + "/alerting/notifications"},
+ {Text: "Notification channels", Url: setting.AppSubUrl + "/alerting/notifications"},
}
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
diff --git a/pkg/services/alerting/notifier.go b/pkg/services/alerting/notifier.go
index 0775b48f2b0..7e213058cd0 100644
--- a/pkg/services/alerting/notifier.go
+++ b/pkg/services/alerting/notifier.go
@@ -13,6 +13,14 @@ import (
m "github.com/grafana/grafana/pkg/models"
)
+type NotifierPlugin struct {
+ Type string `json:"type"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ OptionsTemplate string `json:"optionsTemplate"`
+ Factory NotifierFactory `json:"-"`
+}
+
type RootNotifier struct {
log log.Logger
}
@@ -130,12 +138,12 @@ func (n *RootNotifier) getNotifiers(orgId int64, notificationIds []int64, contex
}
func (n *RootNotifier) createNotifierFor(model *m.AlertNotification) (Notifier, error) {
- factory, found := notifierFactories[model.Type]
+ notifierPlugin, found := notifierFactories[model.Type]
if !found {
return nil, errors.New("Unsupported notification type")
}
- return factory(model)
+ return notifierPlugin.Factory(model)
}
func shouldUseNotification(notifier Notifier, context *EvalContext) bool {
@@ -152,8 +160,18 @@ func shouldUseNotification(notifier Notifier, context *EvalContext) bool {
type NotifierFactory func(notification *m.AlertNotification) (Notifier, error)
-var notifierFactories map[string]NotifierFactory = make(map[string]NotifierFactory)
+var notifierFactories map[string]*NotifierPlugin = make(map[string]*NotifierPlugin)
-func RegisterNotifier(typeName string, factory NotifierFactory) {
- notifierFactories[typeName] = factory
+func RegisterNotifier(plugin *NotifierPlugin) {
+ notifierFactories[plugin.Type] = plugin
+}
+
+func GetNotifiers() []*NotifierPlugin {
+ list := make([]*NotifierPlugin, 0)
+
+ for _, value := range notifierFactories {
+ list = append(list, value)
+ }
+
+ return list
}
diff --git a/pkg/services/alerting/notifiers/email.go b/pkg/services/alerting/notifiers/email.go
index 8cd4273e6be..4058d3860b5 100644
--- a/pkg/services/alerting/notifiers/email.go
+++ b/pkg/services/alerting/notifiers/email.go
@@ -13,7 +13,21 @@ import (
)
func init() {
- alerting.RegisterNotifier("email", NewEmailNotifier)
+ alerting.RegisterNotifier(&alerting.NotifierPlugin{
+ Type: "email",
+ Name: "Email",
+ Description: "Sends notifications using Grafana server configured STMP settings",
+ Factory: NewEmailNotifier,
+ OptionsTemplate: `
+
Email addresses
+
+
+
+
+ You can enter multiple email addresses using a ";" separator
+
+ `,
+ })
}
type EmailNotifier struct {
diff --git a/pkg/services/alerting/notifiers/opsgenie.go b/pkg/services/alerting/notifiers/opsgenie.go
index a93b650d494..742aeb922b6 100644
--- a/pkg/services/alerting/notifiers/opsgenie.go
+++ b/pkg/services/alerting/notifiers/opsgenie.go
@@ -13,7 +13,28 @@ import (
)
func init() {
- alerting.RegisterNotifier("opsgenie", NewOpsGenieNotifier)
+ alerting.RegisterNotifier(&alerting.NotifierPlugin{
+ Type: "opsgenie",
+ Name: "OpsGenie",
+ Description: "Sends notifications to OpsGenie",
+ Factory: NewOpsGenieNotifier,
+ OptionsTemplate: `
+ OpsGenie settings
+
+ API Key
+
+
+
+
+
+
+ `,
+ })
}
var (
diff --git a/pkg/services/alerting/notifiers/pagerduty.go b/pkg/services/alerting/notifiers/pagerduty.go
index e94bd5ebeaa..0c98ab00e20 100644
--- a/pkg/services/alerting/notifiers/pagerduty.go
+++ b/pkg/services/alerting/notifiers/pagerduty.go
@@ -12,7 +12,28 @@ import (
)
func init() {
- alerting.RegisterNotifier("pagerduty", NewPagerdutyNotifier)
+ alerting.RegisterNotifier(&alerting.NotifierPlugin{
+ Type: "pagerduty",
+ Name: "PagerDuty",
+ Description: "Sends notifications to PagerDuty",
+ Factory: NewPagerdutyNotifier,
+ OptionsTemplate: `
+ PagerDuty settings
+
+ Integration Key
+
+
+
+
+
+
+ `,
+ })
}
var (
diff --git a/pkg/services/alerting/notifiers/slack.go b/pkg/services/alerting/notifiers/slack.go
index 2666662e32c..7b2bfd09c9a 100644
--- a/pkg/services/alerting/notifiers/slack.go
+++ b/pkg/services/alerting/notifiers/slack.go
@@ -13,7 +13,42 @@ import (
)
func init() {
- alerting.RegisterNotifier("slack", NewSlackNotifier)
+ alerting.RegisterNotifier(&alerting.NotifierPlugin{
+ Type: "slack",
+ Name: "Slack",
+ Description: "Sends notifications using Grafana server configured STMP settings",
+ Factory: NewSlackNotifier,
+ OptionsTemplate: `
+ Slack settings
+
+ Url
+
+
+
+ Recipient
+
+
+
+ Override default channel or user, use #channel-name or @username
+
+
+
+ Mention
+
+
+
+ Mention a user or a group using @ when notifying in a channel
+
+
+ `,
+ })
+
}
func NewSlackNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
diff --git a/pkg/services/alerting/notifiers/telegram.go b/pkg/services/alerting/notifiers/telegram.go
index 551464733d9..dd3011a49ec 100644
--- a/pkg/services/alerting/notifiers/telegram.go
+++ b/pkg/services/alerting/notifiers/telegram.go
@@ -16,7 +16,34 @@ var (
)
func init() {
- alerting.RegisterNotifier("telegram", NewTelegramNotifier)
+ alerting.RegisterNotifier(&alerting.NotifierPlugin{
+ Type: "telegram",
+ Name: "Telegram",
+ Description: "Sends notifications to Telegram",
+ Factory: NewOpsGenieNotifier,
+ OptionsTemplate: `
+ Telegram API settings
+
+ BOT API Token
+
+
+
+ Chat ID
+
+
+
+ Integer Telegram Chat Identifier
+
+
+ `,
+ })
+
}
type TelegramNotifier struct {
diff --git a/pkg/services/alerting/notifiers/victorops.go b/pkg/services/alerting/notifiers/victorops.go
index 9afa1efb281..a4e34a40b8a 100644
--- a/pkg/services/alerting/notifiers/victorops.go
+++ b/pkg/services/alerting/notifiers/victorops.go
@@ -16,7 +16,19 @@ import (
const AlertStateCritical = "CRITICAL"
func init() {
- alerting.RegisterNotifier("victorops", NewVictoropsNotifier)
+ alerting.RegisterNotifier(&alerting.NotifierPlugin{
+ Type: "victorops",
+ Name: "VictorOps",
+ Description: "Sends notifications to VictorOps",
+ Factory: NewVictoropsNotifier,
+ OptionsTemplate: `
+ VictorOps settings
+
+ Url
+
+
+ `,
+ })
}
// NewVictoropsNotifier creates an instance of VictoropsNotifier that
diff --git a/pkg/services/alerting/notifiers/webhook.go b/pkg/services/alerting/notifiers/webhook.go
index 0603cf45084..25ed22a65f5 100644
--- a/pkg/services/alerting/notifiers/webhook.go
+++ b/pkg/services/alerting/notifiers/webhook.go
@@ -10,7 +10,35 @@ import (
)
func init() {
- alerting.RegisterNotifier("webhook", NewWebHookNotifier)
+ alerting.RegisterNotifier(&alerting.NotifierPlugin{
+ Type: "webhook",
+ Name: "webhook",
+ Description: "Sends HTTP POST request to a URL",
+ Factory: NewWebHookNotifier,
+ OptionsTemplate: `
+ Webhook settings
+
+ Url
+
+
+
+
+ Username
+
+
+
+ Password
+
+
+ `,
+ })
+
}
func NewWebHookNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
diff --git a/public/app/features/alerting/notification_edit_ctrl.ts b/public/app/features/alerting/notification_edit_ctrl.ts
index 77e67d96d86..ed05264cdb3 100644
--- a/public/app/features/alerting/notification_edit_ctrl.ts
+++ b/public/app/features/alerting/notification_edit_ctrl.ts
@@ -2,40 +2,48 @@
import angular from 'angular';
import _ from 'lodash';
-import coreModule from '../../core/core_module';
import config from 'app/core/config';
+import {appEvents, coreModule} from 'app/core/core';
export class AlertNotificationEditCtrl {
- model: any;
theForm: any;
testSeverity: string = "critical";
+ notifiers: any;
+ notifierTemplateId: string;
+
+ model: any;
+ defaults: any = {
+ type: 'email',
+ settings: {
+ httpMethod: 'POST',
+ autoResolve: true,
+ },
+ isDefault: false
+ };
/** @ngInject */
- constructor(private $routeParams, private backendSrv, private $scope, private $location) {
- if ($routeParams.id) {
- this.loadNotification($routeParams.id);
- } else {
- this.model = {
- type: 'email',
- settings: {
- httpMethod: 'POST',
- autoResolve: true,
- },
- isDefault: false
- };
- }
- }
+ constructor(private $routeParams, private backendSrv, private $location, private $templateCache) {
+ this.backendSrv.get(`/api/alert-notifiers`).then(notifiers => {
+ this.notifiers = notifiers;
- loadNotification(id) {
- this.backendSrv.get(`/api/alert-notifications/${id}`).then(result => {
- this.model = result;
+ // add option templates
+ for (let notifier of this.notifiers) {
+ this.$templateCache.put(this.getNotifierTemplateId(notifier.type), notifier.optionsTemplate);
+ }
+
+ if (!this.$routeParams.id) {
+ return this.model;
+ }
+
+ return this.backendSrv.get(`/api/alert-notifications/${this.$routeParams.id}`).then(result => {
+ return result;
+ });
+ }).then(model => {
+ this.model = model;
+ this.notifierTemplateId = this.getNotifierTemplateId(this.model.type);
});
}
- isNew() {
- return this.model.id === undefined;
- }
-
save() {
if (!this.theForm.$valid) {
return;
@@ -44,18 +52,23 @@ export class AlertNotificationEditCtrl {
if (this.model.id) {
this.backendSrv.put(`/api/alert-notifications/${this.model.id}`, this.model).then(res => {
this.model = res;
- this.$scope.appEvent('alert-success', ['Notification updated', '']);
+ appEvents.emit('alert-success', ['Notification updated', '']);
});
} else {
this.backendSrv.post(`/api/alert-notifications`, this.model).then(res => {
- this.$scope.appEvent('alert-success', ['Notification created', '']);
+ appEvents.emit('alert-success', ['Notification created', '']);
this.$location.path('alerting/notifications');
});
}
}
+ getNotifierTemplateId(type) {
+ return `notifier-options-${type}`;
+ }
+
typeChanged() {
this.model.settings = {};
+ this.notifierTemplateId = this.getNotifierTemplateId(this.model.type);
}
testNotification() {
@@ -70,9 +83,9 @@ export class AlertNotificationEditCtrl {
};
this.backendSrv.post(`/api/alert-notifications/test`, payload)
- .then(res => {
- this.$scope.appEvent('alert-succes', ['Test notification sent', '']);
- });
+ .then(res => {
+ appEvents.emit('alert-succes', ['Test notification sent', '']);
+ });
}
}
diff --git a/public/app/features/alerting/partials/notification_edit.html b/public/app/features/alerting/partials/notification_edit.html
index 33f8e1a0f87..dfdfb115f4b 100644
--- a/public/app/features/alerting/partials/notification_edit.html
+++ b/public/app/features/alerting/partials/notification_edit.html
@@ -1,16 +1,17 @@
-
- Notifications
+
+ Notification channels
-