Templates for Slack notifications
This change adds an optional, user configurable template which may be used to format the text contained in Slack notifications. Story: 2001308 Task: 5859 Change-Id: Id936c3dc8b4f3e2430de20c8b69d0e703b1cf9ef
This commit is contained in:
parent
ac837fa3cc
commit
39a906b8fb
92
README.rst
92
README.rst
@ -131,6 +131,94 @@ StatsD server launched by monasca-agent. Default host and port points to
|
||||
- ConfigDBTime
|
||||
- SendNotificationTime
|
||||
|
||||
Plugins
|
||||
-------
|
||||
|
||||
The following notification plugins are available:
|
||||
|
||||
- Email
|
||||
- HipChat
|
||||
- Jira
|
||||
- Pagerduty
|
||||
- Slack
|
||||
- Webhook
|
||||
|
||||
The plugins can be configured via the Monasca Notification config file. In
|
||||
general you will need to follow these steps to enable a plugin:
|
||||
|
||||
- Make sure that the plugin is enabled in the config file
|
||||
- Make sure that the plugin is configured in the config file
|
||||
- Restart the Monasca Notification service
|
||||
|
||||
Slack plugin
|
||||
~~~~~~~~~~~~
|
||||
|
||||
To use the Slack plugin you must first configure an incoming `webhook`_
|
||||
for the Slack channel you wish to post notifications to. The notification can
|
||||
then be created as follows:
|
||||
|
||||
::
|
||||
|
||||
monasca notification-create slack_notification slack https://hooks.slack.com/services/MY/SECRET/WEBHOOK/URL
|
||||
|
||||
Note that whilst it is also possible to use a token instead of a webhook,
|
||||
this approach is now `deprecated`_.
|
||||
|
||||
By default the Slack notification will dump all available information into
|
||||
the alert. For example, a notification may be posted to Slack which looks
|
||||
like this:
|
||||
|
||||
::
|
||||
|
||||
{
|
||||
"metrics":[
|
||||
{
|
||||
"dimensions":{
|
||||
"hostname":"operator"
|
||||
},
|
||||
"id":null,
|
||||
"name":"cpu.user_perc"
|
||||
}
|
||||
],
|
||||
"alarm_id":"20a54a65-44b8-4ac9-a398-1f2d888827d2",
|
||||
"state":"ALARM",
|
||||
"alarm_timestamp":1556703552,
|
||||
"tenant_id":"62f7a7a314904aa3ab137d569d6b4fde",
|
||||
"old_state":"OK",
|
||||
"alarm_description":"Dummy alarm",
|
||||
"message":"Thresholds were exceeded for the sub-alarms: count(cpu.user_perc, deterministic) >= 1.0 with the values: [1.0]",
|
||||
"alarm_definition_id":"78ce7b53-f7e6-4b51-88d0-cb741e7dc906",
|
||||
"alarm_name":"dummy_alarm"
|
||||
}
|
||||
|
||||
The format of the above message can be customised with a Jinja template. All fields
|
||||
from the raw Slack message are available in the template. For example, you may
|
||||
configure the plugin as follows:
|
||||
|
||||
::
|
||||
|
||||
[notification_types]
|
||||
enabled = slack
|
||||
|
||||
[slack_notifier]
|
||||
message_template = /etc/monasca/slack_template.j2
|
||||
timeout = 10
|
||||
ca_certs = /etc/ssl/certs/ca-bundle.crt
|
||||
insecure = False
|
||||
|
||||
With the following contents of `/etc/monasca/slack_template.j2`:
|
||||
|
||||
::
|
||||
|
||||
{{ alarm_name }} has triggered on {% for item in metrics %}host {{ item.dimensions.hostname }}{% if not loop.last %}, {% endif %}{% endfor %}.
|
||||
|
||||
With this configuration, the raw Slack message above would be transformed
|
||||
into:
|
||||
|
||||
::
|
||||
|
||||
dummy_alarm has triggered on host(s): operator.
|
||||
|
||||
Future Considerations
|
||||
=====================
|
||||
|
||||
@ -146,3 +234,7 @@ Future Considerations
|
||||
NotificationEngine instance using webhooks to a local http server. Is
|
||||
that fast enough?
|
||||
- Are we putting too much load on Kafka at ~200 commits per second?
|
||||
|
||||
.. _webhook: https://api.slack.com/incoming-webhooks
|
||||
|
||||
.. _deprecated: https://api.slack.com/custom-integrations/legacy-tokens
|
||||
|
@ -14,11 +14,13 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import requests
|
||||
from six.moves import urllib
|
||||
import ujson as json
|
||||
|
||||
from debtcollector import removals
|
||||
import jinja2
|
||||
from oslo_config import cfg
|
||||
|
||||
from monasca_notification.plugins import abstract_notifier
|
||||
@ -86,10 +88,19 @@ class SlackNotifier(abstract_notifier.AbstractNotifier):
|
||||
'metrics': notification.metrics}
|
||||
|
||||
slack_request = {}
|
||||
slack_request['text'] = json.dumps(body, indent=3)
|
||||
if CONF.slack_notifier.message_template:
|
||||
slack_request['text'] = self._render_message_template(body)
|
||||
else:
|
||||
slack_request['text'] = json.dumps(body, indent=3)
|
||||
|
||||
return slack_request
|
||||
|
||||
def _render_message_template(self, params):
|
||||
path, name = os.path.split(CONF.slack_notifier.message_template)
|
||||
loader = jinja2.FileSystemLoader(path)
|
||||
env = jinja2.Environment(loader=loader, autoescape=True)
|
||||
return env.get_template(name).render(params)
|
||||
|
||||
def _check_response(self, result):
|
||||
if 'application/json' in result.headers.get('Content-Type'):
|
||||
response = result.json()
|
||||
@ -192,7 +203,8 @@ slack_notifier_opts = [
|
||||
cfg.IntOpt(name='timeout', default=5, min=1),
|
||||
cfg.BoolOpt(name='insecure', default=True),
|
||||
cfg.StrOpt(name='ca_certs', default=None),
|
||||
cfg.StrOpt(name='proxy', default=None)
|
||||
cfg.StrOpt(name='proxy', default=None),
|
||||
cfg.StrOpt(name='message_template', default=None)
|
||||
]
|
||||
|
||||
|
||||
|
1
tests/resources/test_slackformat.template
Normal file
1
tests/resources/test_slackformat.template
Normal file
@ -0,0 +1 @@
|
||||
{{ alarm_name }} has triggered on {% for item in metrics %}host {{ metrics[0].dimensions.hostname }}, service {{ item.dimensions.service }}{% if not loop.last %}, {% endif %}{% endfor %}.
|
@ -110,6 +110,15 @@ class TestSlack(base.PluginTestCase):
|
||||
def _validate_post_args(self, post_args, data_format):
|
||||
self.assertEqual(slack_text(),
|
||||
json.loads(post_args.get(data_format).get('text')))
|
||||
self._validate_post_args_base(post_args)
|
||||
|
||||
def _validate_templated_post_args(self, post_args, data_format,
|
||||
expected_slack_text):
|
||||
self.assertEqual(expected_slack_text,
|
||||
post_args.get(data_format).get('text'))
|
||||
self._validate_post_args_base(post_args)
|
||||
|
||||
def _validate_post_args_base(self, post_args):
|
||||
self.assertEqual({'https': 'http://yourid:password@proxyserver:8080'},
|
||||
post_args.get('proxies'))
|
||||
self.assertEqual(50, post_args.get('timeout'))
|
||||
@ -128,6 +137,24 @@ class TestSlack(base.PluginTestCase):
|
||||
self._validate_post_args(mock_method.call_args_list[0][1], 'json')
|
||||
self.assertEqual([], slack_notifier.SlackNotifier._raw_data_url_caches)
|
||||
|
||||
def test_templated_slack_webhook_success(self):
|
||||
"""A templated message is successfully sent as json
|
||||
"""
|
||||
self.conf_override(
|
||||
message_template='tests/resources/test_slackformat.template',
|
||||
group='slack_notifier'
|
||||
)
|
||||
response_list = [RequestsResponse(200, 'ok',
|
||||
{'Content-Type': 'application/text'})]
|
||||
mock_method, result = self._notify(response_list)
|
||||
self.assertTrue(result)
|
||||
mock_method.assert_called_once()
|
||||
expected_text = 'test Alarm has triggered on host foo1, service bar1.'
|
||||
self._validate_templated_post_args(mock_method.call_args_list[0][1],
|
||||
'json',
|
||||
expected_text)
|
||||
self.assertEqual([], slack_notifier.SlackNotifier._raw_data_url_caches)
|
||||
|
||||
def test_slack_webhook_fail(self):
|
||||
"""data is sent twice as json and raw data, and slack returns failure for
|
||||
both requests
|
||||
|
Loading…
Reference in New Issue
Block a user