Make default notifiers pluggable

Erasing distinction between plugins that are an inherent part of the
notification engine and plugins that can be specified via the config file.
Fixing broken tests.

Story: 2003801
Task: 26532
Change-Id: I360cc2ad0782f209606706bf1869570fdae2260d
This commit is contained in:
Joe Keen 2017-02-16 14:56:11 -07:00 committed by Dobroslaw Zybort
parent cedb42da75
commit 1d680f1739
6 changed files with 123 additions and 76 deletions

View File

@ -80,21 +80,6 @@ def load_from_yaml(yaml_config, conf=None):
notifiers_cfg = {t.lower(): v for t, v in notifiers_cfg.items()} notifiers_cfg = {t.lower(): v for t, v in notifiers_cfg.items()}
enabled_plugins = notifiers_cfg.pop('plugins', []) enabled_plugins = notifiers_cfg.pop('plugins', [])
# We still can have these 3 (email, pagerduty, webhook)
# that are considered as builtin, hence should be always enabled
conf_to_plugin = {
'email': 'monasca_notification.plugins.'
'email_notifier:EmailNotifier',
'pagerduty': 'monasca_notification.plugins.'
'pagerduty_notifier:PagerdutyNotifier',
'webhook': 'monasca_notification.plugins.'
'webhook_notifier:WebhookNotifier'
}
for ctp_key, ctp_clazz in conf_to_plugin.items():
if ctp_key in notifiers_cfg and ctp_key not in enabled_plugins:
LOG.debug('%s enabled as builtin plugin', ctp_key)
enabled_plugins.append(ctp_clazz)
_plain_override(g='notification_types', enabled=enabled_plugins) _plain_override(g='notification_types', enabled=enabled_plugins)
if not enabled_plugins: if not enabled_plugins:
return return

View File

@ -14,12 +14,11 @@
from oslo_config import cfg from oslo_config import cfg
# NOTE(kornicameister) Until https://review.openstack.org/#/c/435136/
# is merged we only treat these below as plugins.
# WEBHOOK, EMAIL, PAGERDUTY are now treated as built-in & hardcoded
# user has no possibility of enabling/disabling them
_KEY_MAP = { _KEY_MAP = {
'email': 'monasca_notification.plugins.email_notifier:EmailNotifier',
'pagerduty': 'monasca_notification.plugins.'
'pagerduty_notifier:PagerdutyNotifier',
'webhook': 'monasca_notification.plugins.webhook_notifier:WebhookNotifier',
'hipchat': 'monasca_notification.plugins.hipchat_notifier.HipChatNotifier', 'hipchat': 'monasca_notification.plugins.hipchat_notifier.HipChatNotifier',
'slack': 'monasca_notification.plugins.slack_notifier.SlackNotifier', 'slack': 'monasca_notification.plugins.slack_notifier.SlackNotifier',
'jira': 'monasca_notification.plugins.jira_notifier.JiraNotifier' 'jira': 'monasca_notification.plugins.jira_notifier.JiraNotifier'

View File

@ -21,10 +21,6 @@ from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import importutils from oslo_utils import importutils
from monasca_notification.plugins import email_notifier
from monasca_notification.plugins import pagerduty_notifier
from monasca_notification.plugins import webhook_notifier
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
CONF = cfg.CONF CONF = cfg.CONF
@ -46,12 +42,7 @@ def init(statsd_obj):
statsd_counter = {} statsd_counter = {}
configured_notifiers = {} configured_notifiers = {}
possible_notifiers = []
possible_notifiers = [
email_notifier.EmailNotifier(log),
webhook_notifier.WebhookNotifier(log),
pagerduty_notifier.PagerdutyNotifier(log)
]
def load_plugins(): def load_plugins():

View File

@ -29,6 +29,9 @@ postgresql:
notification_types: notification_types:
plugins: plugins:
- monasca_notification.plugins.email_notifier:EmailNotifier
- monasca_notification.plugins.pagerduty_notifier:PagerdutyNotifier
- monasca_notification.plugins.webhook_notifier:WebhookNotifier
- monasca_notification.plugins.hipchat_notifier:HipChatNotifier - monasca_notification.plugins.hipchat_notifier:HipChatNotifier
- monasca_notification.plugins.slack_notifier:SlackNotifier - monasca_notification.plugins.slack_notifier:SlackNotifier
- monasca_notification.plugins.jira_notifier:JiraNotifier - monasca_notification.plugins.jira_notifier:JiraNotifier

View File

@ -61,7 +61,7 @@ class TestNotificationProcessor(base.BaseTestCase):
# ------------------------------------------------------------------------ # ------------------------------------------------------------------------
@mock.patch('pymysql.connect') @mock.patch('pymysql.connect')
@mock.patch('monasca_notification.common.utils.monascastatsd') @mock.patch('monasca_notification.common.utils.monascastatsd')
@mock.patch('monasca_notification.types.notifiers.email_notifier.smtplib') @mock.patch('monasca_notification.plugins.email_notifier.smtplib')
@mock.patch('monasca_notification.processors.notification_processor.notifiers.log') @mock.patch('monasca_notification.processors.notification_processor.notifiers.log')
def _start_processor(self, notifications, mock_log, mock_smtp, mock_statsd, mock_pymsql): def _start_processor(self, notifications, mock_log, mock_smtp, mock_statsd, mock_pymsql):
"""Start the processor with the proper mocks """Start the processor with the proper mocks

View File

@ -1,4 +1,4 @@
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP # (C) Copyright 2015-2017 Hewlett Packard Enterprise Development LP
# Copyright 2017 Fujitsu LIMITED # Copyright 2017 Fujitsu LIMITED
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
@ -149,55 +149,103 @@ class TestInterface(base.BaseTestCase):
def _goodSendStub(self, log): def _goodSendStub(self, log):
return NotifyStub(self.trap, False, False, False) return NotifyStub(self.trap, False, False, False)
@mock.patch('monasca_notification.types.notifiers.email_notifier.smtplib') def test_enabled_notifications_none(self):
@mock.patch('monasca_notification.types.notifiers.log') self.conf_override(
def test_enabled_notifications(self, mock_log, mock_smtp): group='notification_types',
enabled=[]
)
notifiers.init(self.statsd) notifiers.init(self.statsd)
notifiers.load_plugins()
notifiers.config() notifiers.config()
notifications = notifiers.enabled_notifications() notifications = notifiers.enabled_notifications()
self.assertEqual(len(notifications), 3) self.assertEqual(len(notifications), 0)
self.assertEqual(sorted(notifications),
["EMAIL", "PAGERDUTY", "WEBHOOK"])
@mock.patch('monasca_notification.types.notifiers.email_notifier') def test_enabled_notifications(self):
@mock.patch('monasca_notification.types.notifiers.email_notifier.smtplib') self.conf_override(
group='notification_types',
enabled=[
'monasca_notification.plugins.email_notifier:EmailNotifier',
'monasca_notification.plugins.pagerduty_notifier:PagerdutyNotifier',
'monasca_notification.plugins.webhook_notifier:WebhookNotifier',
'monasca_notification.plugins.hipchat_notifier:HipChatNotifier',
'monasca_notification.plugins.slack_notifier:SlackNotifier',
'monasca_notification.plugins.jira_notifier:JiraNotifier'
]
)
notifiers.init(self.statsd)
notifiers.load_plugins()
notifiers.config()
notifications = notifiers.enabled_notifications()
self.assertEqual(len(notifications), 6)
self.assertItemsEqual(notifications,
['EMAIL', 'PAGERDUTY', 'WEBHOOK',
'HIPCHAT', 'SLACK', 'JIRA'])
@mock.patch('monasca_notification.plugins.email_notifier')
@mock.patch('monasca_notification.plugins.email_notifier.smtplib')
@mock.patch('monasca_notification.types.notifiers.log') @mock.patch('monasca_notification.types.notifiers.log')
def test_send_notification_exception(self, mock_log, mock_smtp, mock_email): @mock.patch('monasca_notification.types.notifiers.importutils')
def test_send_notification_exception(self, mock_im, mock_log,
mock_smtp, mock_email):
self.conf_override(
group='notification_types',
enabled=[
'monasca_notification.plugins.email_notifier:EmailNotifier'
]
)
mock_log.warn = self.trap.append mock_log.warn = self.trap.append
mock_log.error = self.trap.append mock_log.error = self.trap.append
mock_log.exception = self.trap.append mock_log.exception = self.trap.append
mock_email.EmailNotifier = self._sendExceptionStub mock_email.EmailNotifier = self._sendExceptionStub
mock_im.import_class.return_value = mock_email.EmailNotifier
notifiers.init(self.statsd) notifiers.init(self.statsd)
notifiers.load_plugins()
notifiers.config() notifiers.config()
notifications = [] notifications = [
notifications.append(m_notification.Notification(0, 'email', 'email notification', m_notification.Notification(0, 'email', 'email notification',
'me@here.com', 0, 0, alarm({}))) 'me@here.com', 0, 0, alarm({}))
]
notifiers.send_notifications(notifications) notifiers.send_notifications(notifications)
self.assertIn("send_notification exception for email", self.trap) self.assertIn("send_notification exception for email", self.trap)
@mock.patch('monasca_notification.types.notifiers.email_notifier') @mock.patch('monasca_notification.plugins.email_notifier')
@mock.patch('monasca_notification.types.notifiers.email_notifier.smtplib') @mock.patch('monasca_notification.plugins.email_notifier.smtplib')
@mock.patch('monasca_notification.types.notifiers.log') @mock.patch('monasca_notification.types.notifiers.log')
def test_send_notification_failure(self, mock_log, mock_smtp, mock_email): @mock.patch('monasca_notification.types.notifiers.importutils')
def test_send_notification_failure(self, mock_im, mock_log,
mock_smtp, mock_email):
self.conf_override(
group='notification_types',
enabled=[
'monasca_notification.plugins.email_notifier:EmailNotifier'
]
)
mock_log.warn = self.trap.append mock_log.warn = self.trap.append
mock_log.error = self.trap.append mock_log.error = self.trap.append
mock_log.exception = self.trap.append mock_log.exception = self.trap.append
mock_email.EmailNotifier = self._sendFailureStub mock_email.EmailNotifier = self._sendFailureStub
mock_im.import_class.return_value = mock_email.EmailNotifier
notifiers.init(self.statsd) notifiers.init(self.statsd)
notifiers.load_plugins()
notifiers.config() notifiers.config()
notifications = [] notifications = [
notifications.append(m_notification.Notification(0, 'email', 'email notification', m_notification.Notification(0, 'email', 'email notification',
'me@here.com', 0, 0, alarm({}))) 'me@here.com', 0, 0, alarm({}))
]
sent, failed, invalid = notifiers.send_notifications(notifications) sent, failed, invalid = notifiers.send_notifications(notifications)
@ -206,28 +254,38 @@ class TestInterface(base.BaseTestCase):
self.assertEqual(invalid, []) self.assertEqual(invalid, [])
@mock.patch('monasca_notification.types.notifiers.time') @mock.patch('monasca_notification.types.notifiers.time')
@mock.patch('monasca_notification.types.notifiers.email_notifier') @mock.patch('monasca_notification.plugins.email_notifier')
@mock.patch('monasca_notification.types.notifiers.email_notifier.smtplib') @mock.patch('monasca_notification.plugins.email_notifier.smtplib')
@mock.patch('monasca_notification.types.notifiers.log') @mock.patch('monasca_notification.types.notifiers.log')
def test_send_notification_correct(self, mock_log, mock_smtp, @mock.patch('monasca_notification.types.notifiers.importutils')
def test_send_notification_correct(self, mock_im, mock_log, mock_smtp,
mock_email, mock_time): mock_email, mock_time):
self.conf_override(
group='notification_types',
enabled=[
'monasca_notification.plugins.email_notifier:EmailNotifier'
]
)
mock_log.warn = self.trap.append mock_log.warn = self.trap.append
mock_log.error = self.trap.append mock_log.error = self.trap.append
mock_email.EmailNotifier = self._goodSendStub mock_email.EmailNotifier = self._goodSendStub
mock_time.time.return_value = 42 mock_time.time.return_value = 42
mock_im.import_class.return_value = mock_email.EmailNotifier
notifiers.init(self.statsd) notifiers.init(self.statsd)
notifiers.load_plugins()
notifiers.config() notifiers.config()
notifications = [] notifications = [
notifications.append(m_notification.Notification(0, 'email', 'email notification', m_notification.Notification(0, 'email', 'email notification',
'me@here.com', 0, 0, alarm({}))) 'me@here.com', 0, 0, alarm({})),
notifications.append(m_notification.Notification(1, 'email', 'email notification', m_notification.Notification(1, 'email', 'email notification',
'foo@here.com', 0, 0, alarm({}))) 'foo@here.com', 0, 0, alarm({})),
notifications.append(m_notification.Notification(2, 'email', 'email notification', m_notification.Notification(2, 'email', 'email notification',
'bar@here.com', 0, 0, alarm({}))) 'bar@here.com', 0, 0, alarm({}))
]
sent, failed, invalid = notifiers.send_notifications(notifications) sent, failed, invalid = notifiers.send_notifications(notifications)
@ -238,25 +296,36 @@ class TestInterface(base.BaseTestCase):
for n in sent: for n in sent:
self.assertEqual(n.notification_timestamp, 42) self.assertEqual(n.notification_timestamp, 42)
@mock.patch('monasca_notification.types.notifiers.email_notifier') @mock.patch('monasca_notification.plugins.email_notifier')
@mock.patch('monasca_notification.types.notifiers.email_notifier.smtplib') @mock.patch('monasca_notification.plugins.email_notifier.smtplib')
@mock.patch('monasca_notification.types.notifiers.log') @mock.patch('monasca_notification.types.notifiers.log')
def test_statsd(self, mock_log, mock_smtp, mock_email): @mock.patch('monasca_notification.types.notifiers.importutils')
def test_statsd(self, mock_im, mock_log, mock_smtp, mock_email):
self.conf_override(
group='notification_types',
enabled=[
'monasca_notification.plugins.email_notifier:EmailNotifier'
]
)
mock_log.warn = self.trap.append mock_log.warn = self.trap.append
mock_log.error = self.trap.append mock_log.error = self.trap.append
mock_email.EmailNotifier = self._goodSendStub mock_email.EmailNotifier = self._goodSendStub
mock_im.import_class.return_value = mock_email.EmailNotifier
notifiers.init(self.statsd) notifiers.init(self.statsd)
notifiers.load_plugins()
notifiers.config() notifiers.config()
notifications = [] notifications = [
notifications.append(m_notification.Notification(0, 'email', 'email notification', m_notification.Notification(0, 'email', 'email notification',
'me@here.com', 0, 0, alarm({}))) 'me@here.com', 0, 0, alarm({})),
notifications.append(m_notification.Notification(1, 'email', 'email notification', m_notification.Notification(1, 'email', 'email notification',
'foo@here.com', 0, 0, alarm({}))) 'foo@here.com', 0, 0, alarm({})),
notifications.append(m_notification.Notification(2, 'email', 'email notification', m_notification.Notification(2, 'email', 'email notification',
'bar@here.com', 0, 0, alarm({}))) 'bar@here.com', 0, 0, alarm({}))
]
notifiers.send_notifications(notifications) notifiers.send_notifications(notifications)
@ -275,11 +344,11 @@ class TestInterface(base.BaseTestCase):
notifiers.init(self.statsd) notifiers.init(self.statsd)
notifiers.load_plugins() notifiers.load_plugins()
self.assertEqual(len(notifiers.possible_notifiers), 5) notifiers.config()
configured_plugins = ["email", "webhook", "pagerduty", "hipchat", "slack"] self.assertEqual(len(notifiers.possible_notifiers), 2)
for plugin in notifiers.configured_notifiers: self.assertItemsEqual(['hipchat', 'slack'],
self.asssertIn(plugin.type in configured_plugins) notifiers.configured_notifiers)
@mock.patch('monasca_notification.types.notifiers.log') @mock.patch('monasca_notification.types.notifiers.log')
def test_invalid_plugin_load_exception_ignored(self, mock_log): def test_invalid_plugin_load_exception_ignored(self, mock_log):
@ -294,7 +363,7 @@ class TestInterface(base.BaseTestCase):
notifiers.init(self.statsd) notifiers.init(self.statsd)
notifiers.load_plugins() notifiers.load_plugins()
self.assertEqual(len(notifiers.possible_notifiers), 4) self.assertEqual(len(notifiers.possible_notifiers), 1)
self.assertEqual(len(self.trap), 1) self.assertEqual(len(self.trap), 1)
configured_plugins = ["email", "webhook", "pagerduty", "slack"] configured_plugins = ["email", "webhook", "pagerduty", "slack"]