summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Bogott <abogott@wikimedia.org>2012-08-03 20:15:54 -0500
committerAndrew Bogott <abogott@wikimedia.org>2012-08-03 20:37:51 -0500
commitee3cc503f26147087c961089ffbce30810697e80 (patch)
tree12f5988c5bfe1f8e85fd312209eddf0beb088d69
parent0e6ec643c26a7355e4f5e8db7c4fce2786a9f63b (diff)
Migrate a notifier patch from common:
commit c767e9beffe4b826eac869ce7e2eef2cc1499bbe Author: Andrew Bogott <abogott@wikimedia.org> Date: Thu Jul 19 03:34:31 2012 -0500 Add multiple-driver support to the notifier api. Move all of the functionality previously provided by the list_notifier into the basic notifier api. Move and restructure tests accordingly. Remove the list_notifier file and test file. For bug 1025820 Change-Id: Icadaafe8bc312942249272873d9a4a8f1aa49a94
-rw-r--r--nova/openstack/common/log.py7
-rw-r--r--nova/openstack/common/notifier/api.py74
-rw-r--r--nova/openstack/common/notifier/list_notifier.py117
-rw-r--r--nova/openstack/common/plugin/plugin.py1
-rw-r--r--nova/openstack/common/plugin/pluginmanager.py21
-rw-r--r--nova/tests/compute/test_compute.py4
-rw-r--r--nova/tests/compute/test_compute_utils.py7
-rw-r--r--nova/tests/test_notifications.py7
-rw-r--r--nova/tests/test_volume.py4
-rw-r--r--nova/tests/test_volume_utils.py7
10 files changed, 86 insertions, 163 deletions
diff --git a/nova/openstack/common/log.py b/nova/openstack/common/log.py
index 31238062b..e055e8148 100644
--- a/nova/openstack/common/log.py
+++ b/nova/openstack/common/log.py
@@ -247,10 +247,9 @@ class JSONFormatter(logging.Formatter):
class PublishErrorsHandler(logging.Handler):
def emit(self, record):
- if 'list_notifier_drivers' in CONF:
- if ('nova.openstack.common.notifier.log_notifier' in
- CONF.list_notifier_drivers):
- return
+ if ('nova.openstack.common.notifier.log_notifier' in
+ CONF.notification_driver):
+ return
notifier.api.notify(None, 'error.publisher',
'error_notification',
notifier.api.ERROR,
diff --git a/nova/openstack/common/notifier/api.py b/nova/openstack/common/notifier/api.py
index ba6c2dd9f..f90a4eba8 100644
--- a/nova/openstack/common/notifier/api.py
+++ b/nova/openstack/common/notifier/api.py
@@ -28,16 +28,17 @@ from nova.openstack.common import timeutils
LOG = logging.getLogger(__name__)
notifier_opts = [
- cfg.StrOpt('notification_driver',
- default='nova.openstack.common.notifier.no_op_notifier',
- help='Default driver for sending notifications'),
+ cfg.MultiStrOpt('notification_driver',
+ default=[],
+ deprecated_name='list_notifier_drivers',
+ help='Driver or drivers to handle sending notifications'),
cfg.StrOpt('default_notification_level',
default='INFO',
help='Default notification level for outgoing notifications'),
cfg.StrOpt('default_publisher_id',
default='$host',
help='Default publisher_id for outgoing notifications'),
- ]
+]
CONF = cfg.CONF
CONF.register_opts(notifier_opts)
@@ -122,21 +123,60 @@ def notify(context, publisher_id, event_type, priority, payload):
"""
if priority not in log_levels:
raise BadPriorityException(
- _('%s not in valid priorities') % priority)
+ _('%s not in valid priorities') % priority)
# Ensure everything is JSON serializable.
payload = jsonutils.to_primitive(payload, convert_instances=True)
- driver = importutils.import_module(CONF.notification_driver)
msg = dict(message_id=str(uuid.uuid4()),
- publisher_id=publisher_id,
- event_type=event_type,
- priority=priority,
- payload=payload,
- timestamp=str(timeutils.utcnow()))
- try:
- driver.notify(context, msg)
- except Exception, e:
- LOG.exception(_("Problem '%(e)s' attempting to "
- "send to notification system. Payload=%(payload)s") %
- locals())
+ publisher_id=publisher_id,
+ event_type=event_type,
+ priority=priority,
+ payload=payload,
+ timestamp=str(timeutils.utcnow()))
+
+ for driver in _get_drivers():
+ try:
+ driver.notify(context, msg)
+ except Exception, e:
+ LOG.exception(_("Problem '%(e)s' attempting to "
+ "send to notification system. Payload=%(payload)s") %
+ locals())
+
+
+_drivers = None
+
+
+def _get_drivers():
+ """Instantiate, cache, and return drivers based on the CONF."""
+ global _drivers
+ if _drivers is None:
+ _drivers = {}
+ for notification_driver in CONF.notification_driver:
+ add_driver(notification_driver)
+
+ return _drivers.values()
+
+
+def add_driver(notification_driver):
+ """Add a notification driver at runtime."""
+ # Make sure the driver list is initialized.
+ _get_drivers()
+ if isinstance(notification_driver, basestring):
+ # Load and add
+ try:
+ driver = importutils.import_module(notification_driver)
+ _drivers[notification_driver] = driver
+ except ImportError as e:
+ LOG.exception(_("Failed to load notifier %s. "
+ "These notifications will not be sent.") %
+ notification_driver)
+ else:
+ # Driver is already loaded; just add the object.
+ _drivers[notification_driver] = notification_driver
+
+
+def _reset_drivers():
+ """Used by unit tests to reset the drivers."""
+ global _drivers
+ _drivers = None
diff --git a/nova/openstack/common/notifier/list_notifier.py b/nova/openstack/common/notifier/list_notifier.py
deleted file mode 100644
index f59106d9a..000000000
--- a/nova/openstack/common/notifier/list_notifier.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# Copyright 2011 OpenStack LLC.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from nova.openstack.common import cfg
-from nova.openstack.common.gettextutils import _
-from nova.openstack.common import importutils
-from nova.openstack.common import log as logging
-
-
-list_notifier_drivers_opt = cfg.MultiStrOpt('list_notifier_drivers',
- default=['nova.openstack.common.notifier.no_op_notifier'],
- help='List of drivers to send notifications')
-
-CONF = cfg.CONF
-CONF.register_opt(list_notifier_drivers_opt)
-
-LOG = logging.getLogger(__name__)
-
-drivers = None
-
-
-class ImportFailureNotifier(object):
- """Noisily re-raises some exception over-and-over when notify is called."""
-
- def __init__(self, exception):
- self.exception = exception
-
- def notify(self, context, message):
- raise self.exception
-
-
-def _get_drivers():
- """Instantiates and returns drivers based on the flag values."""
- global drivers
- if drivers is None:
- drivers = []
- for notification_driver in CONF.list_notifier_drivers:
- try:
- drivers.append(importutils.import_module(notification_driver))
- except ImportError as e:
- drivers.append(ImportFailureNotifier(e))
- return drivers
-
-
-def add_driver(notification_driver):
- """Add a notification driver at runtime."""
- # Make sure the driver list is initialized.
- _get_drivers()
- if isinstance(notification_driver, basestring):
- # Load and add
- try:
- drivers.append(importutils.import_module(notification_driver))
- except ImportError as e:
- drivers.append(ImportFailureNotifier(e))
- else:
- # Driver is already loaded; just add the object.
- drivers.append(notification_driver)
-
-
-def _object_name(obj):
- name = []
- if hasattr(obj, '__module__'):
- name.append(obj.__module__)
- if hasattr(obj, '__name__'):
- name.append(obj.__name__)
- else:
- name.append(obj.__class__.__name__)
- return '.'.join(name)
-
-
-def remove_driver(notification_driver):
- """Remove a notification driver at runtime."""
- # Make sure the driver list is initialized.
- _get_drivers()
- removed = False
- if notification_driver in drivers:
- # We're removing an object. Easy.
- drivers.remove(notification_driver)
- removed = True
- else:
- # We're removing a driver by name. Search for it.
- for driver in drivers:
- if _object_name(driver) == notification_driver:
- drivers.remove(driver)
- removed = True
-
- if not removed:
- raise ValueError("Cannot remove; %s is not in list" %
- notification_driver)
-
-
-def notify(context, message):
- """Passes notification to multiple notifiers in a list."""
- for driver in _get_drivers():
- try:
- driver.notify(context, message)
- except Exception as e:
- LOG.exception(_("Problem '%(e)s' attempting to send to "
- "notification driver %(driver)s."), locals())
-
-
-def _reset_drivers():
- """Used by unit tests to reset the drivers."""
- global drivers
- drivers = None
diff --git a/nova/openstack/common/plugin/plugin.py b/nova/openstack/common/plugin/plugin.py
index 3db753d65..96be0af82 100644
--- a/nova/openstack/common/plugin/plugin.py
+++ b/nova/openstack/common/plugin/plugin.py
@@ -14,7 +14,6 @@
# under the License.
from nova.openstack.common import log as logging
-from nova.openstack.common.notifier import list_notifier
LOG = logging.getLogger(__name__)
diff --git a/nova/openstack/common/plugin/pluginmanager.py b/nova/openstack/common/plugin/pluginmanager.py
index 6b921656a..29656477d 100644
--- a/nova/openstack/common/plugin/pluginmanager.py
+++ b/nova/openstack/common/plugin/pluginmanager.py
@@ -19,7 +19,7 @@ import pkg_resources
from nova.openstack.common import cfg
from nova.openstack.common import log as logging
-from nova.openstack.common.notifier import list_notifier
+from nova.openstack.common.notifier import api as notifier_api
CONF = cfg.CONF
@@ -53,17 +53,6 @@ class PluginManager(object):
self._service_name = service_name
self.plugins = []
- def _force_use_list_notifier(self):
- if (CONF.notification_driver !=
- 'nova.openstack.common.notifier.list_notifier'):
- if not hasattr(CONF, "list_notifier_drivers"):
- CONF.list_notifier_drivers = []
- old_notifier = CONF.notification_driver
- drvstring = 'nova.openstack.common.notifier.list_notifier'
- CONF.notification_driver = drvstring
- if old_notifier:
- list_notifier.add_driver(old_notifier)
-
def load_plugins(self):
self.plugins = []
@@ -77,16 +66,10 @@ class PluginManager(object):
LOG.error(_("Failed to load plugin %(plug)s: %(exc)s") %
{'plug': entrypoint, 'exc': exc})
- # See if we need to turn on the list notifier
- for plugin in self.plugins:
- if plugin.notifiers:
- self._force_use_list_notifier()
- break
-
# Register individual notifiers.
for plugin in self.plugins:
for notifier in plugin.notifiers:
- list_notifier.add_driver(notifier)
+ notifier_api.add_driver(notifier)
def plugin_extension_factory(self, ext_mgr):
for plugin in self.plugins:
diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py
index bc60233dd..9a647953a 100644
--- a/nova/tests/compute/test_compute.py
+++ b/nova/tests/compute/test_compute.py
@@ -42,6 +42,7 @@ from nova import flags
from nova.openstack.common import importutils
from nova.openstack.common import jsonutils
from nova.openstack.common import log as logging
+from nova.openstack.common.notifier import api as notifier_api
from nova.openstack.common.notifier import test_notifier
from nova.openstack.common import policy as common_policy
from nova.openstack.common import rpc
@@ -114,7 +115,7 @@ class BaseTestCase(test.TestCase):
super(BaseTestCase, self).setUp()
self.flags(compute_driver='nova.virt.fake.FakeDriver',
stub_network=True,
- notification_driver='nova.openstack.common.notifier.test_notifier',
+ notification_driver=['nova.openstack.common.notifier.test_notifier'],
network_manager='nova.network.manager.FlatManager')
self.compute = importutils.import_object(FLAGS.compute_manager)
@@ -142,6 +143,7 @@ class BaseTestCase(test.TestCase):
def tearDown(self):
fake_image.FakeImageService_reset()
instances = db.instance_get_all(self.context.elevated())
+ notifier_api._reset_drivers()
for instance in instances:
db.instance_destroy(self.context.elevated(), instance['uuid'])
super(BaseTestCase, self).tearDown()
diff --git a/nova/tests/compute/test_compute_utils.py b/nova/tests/compute/test_compute_utils.py
index d717182af..40e1947e6 100644
--- a/nova/tests/compute/test_compute_utils.py
+++ b/nova/tests/compute/test_compute_utils.py
@@ -24,6 +24,7 @@ from nova import db
from nova import flags
from nova.openstack.common import importutils
from nova.openstack.common import log as logging
+from nova.openstack.common.notifier import api as notifier_api
from nova.openstack.common.notifier import test_notifier
from nova import test
from nova.tests import fake_network
@@ -50,7 +51,7 @@ class UsageInfoTestCase(test.TestCase):
self.flags(compute_driver='nova.virt.fake.FakeDriver',
stub_network=True,
- notification_driver='nova.openstack.common.notifier.test_notifier',
+ notification_driver=['nova.openstack.common.notifier.test_notifier'],
network_manager='nova.network.manager.FlatManager')
self.compute = importutils.import_object(FLAGS.compute_manager)
self.user_id = 'fake'
@@ -64,6 +65,10 @@ class UsageInfoTestCase(test.TestCase):
self.stubs.Set(nova.tests.image.fake._FakeImageService,
'show', fake_show)
+ def tearDown(self):
+ notifier_api._reset_drivers()
+ super(UsageInfoTestCase, self).tearDown()
+
def _create_instance(self, params={}):
"""Create a test instance"""
inst = {}
diff --git a/nova/tests/test_notifications.py b/nova/tests/test_notifications.py
index 5fd5d63f9..4d2ae57e3 100644
--- a/nova/tests/test_notifications.py
+++ b/nova/tests/test_notifications.py
@@ -28,6 +28,7 @@ from nova import flags
import nova.network
from nova import notifications
from nova.openstack.common import log as logging
+from nova.openstack.common.notifier import api as notifier_api
from nova.openstack.common.notifier import test_notifier
from nova import test
from nova.tests import fake_network
@@ -54,7 +55,7 @@ class NotificationsTestCase(test.TestCase):
self.flags(compute_driver='nova.virt.fake.FakeDriver',
stub_network=True,
- notification_driver='nova.openstack.common.notifier.test_notifier',
+ notification_driver=['nova.openstack.common.notifier.test_notifier'],
network_manager='nova.network.manager.FlatManager',
notify_on_state_change="vm_and_task_state",
host='testhost')
@@ -66,6 +67,10 @@ class NotificationsTestCase(test.TestCase):
self.instance = self._wrapped_create()
+ def tearDown(self):
+ notifier_api._reset_drivers()
+ super(NotificationsTestCase, self).tearDown()
+
def _wrapped_create(self, params=None):
inst = {}
inst['image_ref'] = 1
diff --git a/nova/tests/test_volume.py b/nova/tests/test_volume.py
index aef0b57fc..57ca52786 100644
--- a/nova/tests/test_volume.py
+++ b/nova/tests/test_volume.py
@@ -30,6 +30,7 @@ from nova import exception
from nova import flags
from nova.openstack.common import importutils
from nova.openstack.common import log as logging
+from nova.openstack.common.notifier import api as notifier_api
from nova.openstack.common.notifier import test_notifier
from nova.openstack.common import rpc
import nova.policy
@@ -50,7 +51,7 @@ class VolumeTestCase(test.TestCase):
self.compute = importutils.import_object(FLAGS.compute_manager)
self.flags(compute_driver='nova.virt.fake.FakeDriver')
self.stubs.Set(nova.flags.FLAGS, 'notification_driver',
- 'nova.openstack.common.notifier.test_notifier')
+ ['nova.openstack.common.notifier.test_notifier'])
self.volume = importutils.import_object(FLAGS.volume_manager)
self.context = context.get_admin_context()
instance = db.instance_create(self.context, {})
@@ -60,6 +61,7 @@ class VolumeTestCase(test.TestCase):
def tearDown(self):
db.instance_destroy(self.context, self.instance_uuid)
+ notifier_api._reset_drivers()
super(VolumeTestCase, self).tearDown()
@staticmethod
diff --git a/nova/tests/test_volume_utils.py b/nova/tests/test_volume_utils.py
index 8d0caab24..cd81e67f0 100644
--- a/nova/tests/test_volume_utils.py
+++ b/nova/tests/test_volume_utils.py
@@ -22,6 +22,7 @@ from nova import db
from nova import flags
from nova.openstack.common import importutils
from nova.openstack.common import log as logging
+from nova.openstack.common.notifier import api as notifier_api
from nova.openstack.common.notifier import test_notifier
from nova import test
from nova.volume import utils as volume_utils
@@ -39,7 +40,7 @@ class UsageInfoTestCase(test.TestCase):
stub_network=True,
host='fake')
self.stubs.Set(flags.FLAGS, 'notification_driver',
- 'nova.openstack.common.notifier.test_notifier')
+ ['nova.openstack.common.notifier.test_notifier'])
self.volume = importutils.import_object(FLAGS.volume_manager)
self.user_id = 'fake'
self.project_id = 'fake'
@@ -48,6 +49,10 @@ class UsageInfoTestCase(test.TestCase):
self.context = context.RequestContext(self.user_id, self.project_id)
test_notifier.NOTIFICATIONS = []
+ def tearDown(self):
+ notifier_api._reset_drivers()
+ super(UsageInfoTestCase, self).tearDown()
+
def _create_volume(self, params={}):
"""Create a test volume"""
vol = {}