Merge pull request #103 from ragingpastry/add-mattermost-notification

Add mattermost notification
This commit is contained in:
Matthew Jones 2017-09-15 06:42:37 -07:00 committed by GitHub
commit 4657f29df9
7 changed files with 128 additions and 2 deletions

View File

@ -157,7 +157,7 @@ class Migration(migrations.Migration):
('status', models.CharField(default=b'pending', max_length=20, editable=False, choices=[(b'pending', 'Pending'), (b'successful', 'Successful'), (b'failed', 'Failed')])),
('error', models.TextField(default=b'', editable=False, blank=True)),
('notifications_sent', models.IntegerField(default=0, editable=False)),
('notification_type', models.CharField(max_length=32, choices=[(b'email', 'Email'), (b'slack', 'Slack'), (b'twilio', 'Twilio'), (b'pagerduty', 'Pagerduty'), (b'hipchat', 'HipChat'), (b'webhook', 'Webhook'), (b'irc', 'IRC')])),
('notification_type', models.CharField(max_length=32, choices=[(b'email', 'Email'), (b'slack', 'Slack'), (b'twilio', 'Twilio'), (b'pagerduty', 'Pagerduty'), (b'hipchat', 'HipChat'), (b'webhook', 'Webhook'), (b'mattermost', 'Mattermost'), (b'irc', 'IRC')])),
('recipients', models.TextField(default=b'', editable=False, blank=True)),
('subject', models.TextField(default=b'', editable=False, blank=True)),
('body', jsonfield.fields.JSONField(default=dict, blank=True)),
@ -174,7 +174,7 @@ class Migration(migrations.Migration):
('modified', models.DateTimeField(default=None, editable=False)),
('description', models.TextField(default=b'', blank=True)),
('name', models.CharField(unique=True, max_length=512)),
('notification_type', models.CharField(max_length=32, choices=[(b'email', 'Email'), (b'slack', 'Slack'), (b'twilio', 'Twilio'), (b'pagerduty', 'Pagerduty'), (b'hipchat', 'HipChat'), (b'webhook', 'Webhook'), (b'irc', 'IRC')])),
('notification_type', models.CharField(max_length=32, choices=[(b'email', 'Email'), (b'slack', 'Slack'), (b'twilio', 'Twilio'), (b'pagerduty', 'Pagerduty'), (b'hipchat', 'HipChat'), (b'webhook', 'Webhook'), (b'mattermost', 'Mattermost'), (b'irc', 'IRC')])),
('notification_configuration', jsonfield.fields.JSONField(default=dict)),
('created_by', models.ForeignKey(related_name="{u'class': 'notificationtemplate', u'app_label': 'main'}(class)s_created+", on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),
('modified_by', models.ForeignKey(related_name="{u'class': 'notificationtemplate', u'app_label': 'main'}(class)s_modified+", on_delete=django.db.models.deletion.SET_NULL, default=None, editable=False, to=settings.AUTH_USER_MODEL, null=True)),

View File

@ -12,6 +12,7 @@ from awx.main.notifications.slack_backend import SlackBackend
from awx.main.notifications.twilio_backend import TwilioBackend
from awx.main.notifications.pagerduty_backend import PagerDutyBackend
from awx.main.notifications.hipchat_backend import HipChatBackend
from awx.main.notifications.mattermost_backend import MattermostBackend
from awx.main.notifications.webhook_backend import WebhookBackend
from awx.main.notifications.irc_backend import IrcBackend
@ -25,6 +26,7 @@ NOTIFICATION_TYPES = [('email', _('Email'), CustomEmailBackend),
('twilio', _('Twilio'), TwilioBackend),
('pagerduty', _('Pagerduty'), PagerDutyBackend),
('hipchat', _('HipChat'), HipChatBackend),
('mattermost', _('Mattermost'), MattermostBackend),
('webhook', _('Webhook'), WebhookBackend),
('irc', _('IRC'), IrcBackend)]

View File

@ -19,6 +19,7 @@ from awx.main.notifications.twilio_backend import TwilioBackend
from awx.main.notifications.pagerduty_backend import PagerDutyBackend
from awx.main.notifications.hipchat_backend import HipChatBackend
from awx.main.notifications.webhook_backend import WebhookBackend
from awx.main.notifications.mattermost_backend import MattermostBackend
from awx.main.notifications.irc_backend import IrcBackend
from awx.main.fields import JSONField
@ -36,6 +37,7 @@ class NotificationTemplate(CommonModelNameNotUnique):
('pagerduty', _('Pagerduty'), PagerDutyBackend),
('hipchat', _('HipChat'), HipChatBackend),
('webhook', _('Webhook'), WebhookBackend),
('mattermost', _('Mattermost'), MattermostBackend),
('irc', _('IRC'), IrcBackend)]
NOTIFICATION_TYPE_CHOICES = [(x[0], x[1]) for x in NOTIFICATION_TYPES]
CLASS_FOR_NOTIFICATION_TYPE = dict([(x[0], x[2]) for x in NOTIFICATION_TYPES])

View File

@ -0,0 +1,52 @@
# Copyright (c) 2016 Ansible, Inc.
# All Rights Reserved.
import logging
import requests
import json
from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
from awx.main.notifications.base import AWXBaseEmailBackend
logger = logging.getLogger('awx.main.notifications.mattermost_backend')
class MattermostBackend(AWXBaseEmailBackend):
init_parameters = {"mattermost_url": {"label": "Target URL", "type": "string"},
"mattermost_no_verify_ssl": {"label": "Verify SSL", "type": "bool"}}
recipient_parameter = "mattermost_url"
sender_parameter = None
def __init__(self, mattermost_no_verify_ssl=False, mattermost_channel=None, mattermost_username=None,
mattermost_icon_url=None, fail_silently=False, **kwargs):
super(MattermostBackend, self).__init__(fail_silently=fail_silently)
self.mattermost_channel = mattermost_channel
self.mattermost_username = mattermost_username
self.mattermost_icon_url = mattermost_icon_url
self.mattermost_no_verify_ssl = mattermost_no_verify_ssl
def format_body(self, body):
return body
def send_messages(self, messages):
sent_messages = 0
for m in messages:
payload = {}
for opt, optval in {'mattermost_icon_url':'icon_url',
'mattermost_channel': 'channel', 'mattermost_username': 'username'}.iteritems():
optvalue = getattr(self, opt)
if optvalue is not None:
payload[optval] = optvalue.strip()
payload['text'] = m.subject
r = requests.post("{}".format(m.recipients()[0]),
data=json.dumps(payload), verify=(not self.mattermost_no_verify_ssl))
if r.status_code >= 400:
logger.error(smart_text(_("Error sending notification mattermost: {}").format(r.text)))
if not self.fail_silently:
raise Exception(smart_text(_("Error sending notification mattermost: {}").format(r.text)))
sent_messages += 1
return sent_messages

View File

@ -333,6 +333,45 @@ export default ['i18n', function(i18n) {
subForm: 'typeSubForm',
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
},
mattermost_url: {
label: i18n._('Target URL'),
type: 'text',
awRequiredWhen: {
reqExpression: "mattermost_required",
init: "false"
},
ngShow: "notification_type.value == 'mattermost' ",
subForm: 'typeSubForm',
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
},
mattermost_username: {
label: i18n._('Username'),
type: 'text',
ngShow: "notification_type.value == 'mattermost' ",
subForm: 'typeSubForm',
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
},
mattermost_channel: {
label: i18n._('Channel'),
type: 'text',
ngShow: "notification_type.value == 'mattermost' ",
subForm: 'typeSubForm',
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
},
mattermost_icon_url: {
label: i18n._('Icon URL'),
type: 'text',
ngShow: "notification_type.value == 'mattermost' ",
subForm: 'typeSubForm',
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
},
mattermost_no_verify_ssl: {
label: i18n._('Disable SSL Verification'),
type: 'checkbox',
ngShow: "notification_type.value == 'mattermost' ",
subForm: 'typeSubForm',
ngDisabled: '!(notification_template.summary_fields.user_capabilities.edit || canAdd)'
},
server: {
label: i18n._('IRC Server Address'),
type: 'text',

View File

@ -17,6 +17,7 @@ function (i18n) {
obj.irc_required = false;
obj.twilio_required = false;
obj.webhook_required = false;
obj.mattermost_required = false;
obj.token_required = false;
obj.port_required = false;
obj.password_required = false;
@ -48,6 +49,9 @@ function (i18n) {
case 'webhook':
obj.webhook_required = true;
break;
case 'mattermost':
obj.mattermost_required = true;
break;
case 'pagerduty':
obj.tokenLabel = ' ' + i18n._('API Token');
obj.pagerduty_required = true;

View File

@ -35,6 +35,7 @@ The currently defined Notification Types are:
* Email
* Slack
* Hipchat
* Mattermost
* Pagerduty
* Twilio
* IRC
@ -99,6 +100,32 @@ Hipchat allows you to create a team with limited users and message history for f
https://www.hipchat.com/server
## Mattermost
The mattermost notification integration uses Incoming Webhooks. A password is not required because the webhook URL itself is the secret. Webhooks must be enabled in the System Console of Mattermost. If the user wishes to allow Ansible Tower notifications to modify the Icon URL and username of the notification then they must enabled these options as well.
In order to enable these settings in Mattermost:
1. First go to System Console > Integrations > Custom Integrations. Check Enable Incoming Webhooks
2. Optionally, go to System Console > Integrations > Custom Integrations. Check "Enable integrations to override usernames" and Check "Enable integrations to override profile picture icons"
3. Go to Main Menu > Integrations > Incoming Webhook. Click "Add Incoming Webhook"
4. Choose a "Display Name", "Description", and Channel. This channel will be overridden if the notification uses the `channel` option
* `url`: The incoming webhook URL that was configured in Mattermost. Notifications will use this URL to POST.
* `username`: Optional. The username to display for the notification.
* `channel`: Optional. Override the channel to display the notification in. Mattermost incoming webhooks are tied to a channel by default, so if left blank then this will use the incoming webhook channel. Note, if the channel does not exist then the notification will error out.
* `icon_url`: Optional. A URL pointing to an icon to use for the notification.
### Testing considerations
* Make sure all options behave as expected
* Test that all notification options are obeyed
* Test formatting and appearance. Mattermost will use the minimal version of the notification.
### Test Service
* Utilize an existing Mattermost installation or use their docker container here: `docker run --name mattermost-preview -d --publish 8065:8065 mattermost/mattermost-preview`
* Turn on Incoming Webhooks and optionally allow Integrations to override usernames and icons in the System Console.
## Pagerduty
Pager duty is a fairly straightforward integration. The user will create an API Key in the pagerduty system (this will be the token that is given to Tower) and then create a "Service" which will provide an "Integration Key" that will be given to Tower also. The other options of note are: