Merge "Switch to common notifiers."
This commit is contained in:
@@ -316,9 +316,6 @@ global_opts = [
|
|||||||
cfg.StrOpt('node_availability_zone',
|
cfg.StrOpt('node_availability_zone',
|
||||||
default='nova',
|
default='nova',
|
||||||
help='availability zone of this node'),
|
help='availability zone of this node'),
|
||||||
cfg.StrOpt('notification_driver',
|
|
||||||
default='nova.notifier.no_op_notifier',
|
|
||||||
help='Default driver for sending notifications'),
|
|
||||||
cfg.ListOpt('memcached_servers',
|
cfg.ListOpt('memcached_servers',
|
||||||
default=None,
|
default=None,
|
||||||
help='Memcached servers or None for in process cache.'),
|
help='Memcached servers or None for in process cache.'),
|
||||||
|
|||||||
@@ -1,14 +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.
|
|
||||||
@@ -1,138 +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.
|
|
||||||
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
from nova import exception
|
|
||||||
from nova import flags
|
|
||||||
from nova.openstack.common import cfg
|
|
||||||
from nova.openstack.common import importutils
|
|
||||||
from nova.openstack.common import jsonutils
|
|
||||||
from nova.openstack.common import log as logging
|
|
||||||
from nova.openstack.common import timeutils
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
notifier_opts = [
|
|
||||||
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'),
|
|
||||||
]
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
|
||||||
FLAGS.register_opts(notifier_opts)
|
|
||||||
|
|
||||||
WARN = 'WARN'
|
|
||||||
INFO = 'INFO'
|
|
||||||
ERROR = 'ERROR'
|
|
||||||
CRITICAL = 'CRITICAL'
|
|
||||||
DEBUG = 'DEBUG'
|
|
||||||
|
|
||||||
log_levels = (DEBUG, WARN, INFO, ERROR, CRITICAL)
|
|
||||||
|
|
||||||
|
|
||||||
class BadPriorityException(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def notify_decorator(name, fn):
|
|
||||||
""" decorator for notify which is used from utils.monkey_patch()
|
|
||||||
|
|
||||||
:param name: name of the function
|
|
||||||
:param function: - object of the function
|
|
||||||
:returns: function -- decorated function
|
|
||||||
|
|
||||||
"""
|
|
||||||
def wrapped_func(*args, **kwarg):
|
|
||||||
body = {}
|
|
||||||
body['args'] = []
|
|
||||||
body['kwarg'] = {}
|
|
||||||
for arg in args:
|
|
||||||
body['args'].append(arg)
|
|
||||||
for key in kwarg:
|
|
||||||
body['kwarg'][key] = kwarg[key]
|
|
||||||
|
|
||||||
context = exception.get_context_from_function_and_args(fn, args, kwarg)
|
|
||||||
notify(context,
|
|
||||||
FLAGS.default_publisher_id,
|
|
||||||
name,
|
|
||||||
FLAGS.default_notification_level,
|
|
||||||
body)
|
|
||||||
return fn(*args, **kwarg)
|
|
||||||
return wrapped_func
|
|
||||||
|
|
||||||
|
|
||||||
def publisher_id(service, host=None):
|
|
||||||
if not host:
|
|
||||||
host = FLAGS.host
|
|
||||||
return "%s.%s" % (service, host)
|
|
||||||
|
|
||||||
|
|
||||||
def notify(context, publisher_id, event_type, priority, payload):
|
|
||||||
"""Sends a notification using the specified driver
|
|
||||||
|
|
||||||
:param publisher_id: the source worker_type.host of the message
|
|
||||||
:param event_type: the literal type of event (ex. Instance Creation)
|
|
||||||
:param priority: patterned after the enumeration of Python logging
|
|
||||||
levels in the set (DEBUG, WARN, INFO, ERROR, CRITICAL)
|
|
||||||
:param payload: A python dictionary of attributes
|
|
||||||
|
|
||||||
Outgoing message format includes the above parameters, and appends the
|
|
||||||
following:
|
|
||||||
|
|
||||||
message_id
|
|
||||||
a UUID representing the id for this notification
|
|
||||||
|
|
||||||
timestamp
|
|
||||||
the GMT timestamp the notification was sent at
|
|
||||||
|
|
||||||
The composite message will be constructed as a dictionary of the above
|
|
||||||
attributes, which will then be sent via the transport mechanism defined
|
|
||||||
by the driver.
|
|
||||||
|
|
||||||
Message example::
|
|
||||||
|
|
||||||
{'message_id': str(uuid.uuid4()),
|
|
||||||
'publisher_id': 'compute.host1',
|
|
||||||
'timestamp': timeutils.utcnow(),
|
|
||||||
'priority': 'WARN',
|
|
||||||
'event_type': 'compute.create_instance',
|
|
||||||
'payload': {'instance_id': 12, ... }}
|
|
||||||
|
|
||||||
"""
|
|
||||||
if priority not in log_levels:
|
|
||||||
raise BadPriorityException(
|
|
||||||
_('%s not in valid priorities') % priority)
|
|
||||||
|
|
||||||
# Ensure everything is JSON serializable.
|
|
||||||
payload = jsonutils.to_primitive(payload, convert_instances=True)
|
|
||||||
|
|
||||||
driver = importutils.import_module(FLAGS.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())
|
|
||||||
@@ -1,81 +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 import context
|
|
||||||
from nova import db
|
|
||||||
from nova.openstack.common import log as logging
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def notify(_context, message):
|
|
||||||
"""Look for specific compute manager events and interprete them
|
|
||||||
so as to keep the Capacity table up to date.
|
|
||||||
|
|
||||||
NOTE: the True/False return codes are only for testing.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# The event_type must start with 'compute.instance.'
|
|
||||||
event_type = message.get('event_type', None)
|
|
||||||
preamble = 'compute.instance.'
|
|
||||||
if not event_type or not event_type.startswith(preamble):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Events we're interested in end with .start and .end
|
|
||||||
event = event_type[len(preamble):]
|
|
||||||
parts = event.split('.')
|
|
||||||
suffix = parts[-1].lower()
|
|
||||||
event = event[:(-len(suffix) - 1)]
|
|
||||||
|
|
||||||
if suffix not in ['start', 'end']:
|
|
||||||
return False
|
|
||||||
started = suffix == 'start'
|
|
||||||
ended = suffix == 'end'
|
|
||||||
|
|
||||||
if started and event == 'create':
|
|
||||||
# We've already updated this stuff in the scheduler. Don't redo the
|
|
||||||
# work here.
|
|
||||||
return False
|
|
||||||
|
|
||||||
work = 1 if started else -1
|
|
||||||
|
|
||||||
# Extract the host name from the publisher id ...
|
|
||||||
publisher_preamble = 'compute.'
|
|
||||||
publisher = message.get('publisher_id', None)
|
|
||||||
if not publisher or not publisher.startswith(publisher_preamble):
|
|
||||||
return False
|
|
||||||
host = publisher[len(publisher_preamble):]
|
|
||||||
|
|
||||||
# If we deleted an instance, make sure we reclaim the resources.
|
|
||||||
# We may need to do something explicit for rebuild/migrate.
|
|
||||||
free_ram_mb = 0
|
|
||||||
free_disk_gb = 0
|
|
||||||
vms = 0
|
|
||||||
if ended and event == 'delete':
|
|
||||||
vms = -1
|
|
||||||
payload = message.get('payload', {})
|
|
||||||
free_ram_mb = payload.get('memory_mb', 0)
|
|
||||||
free_disk_gb = payload.get('disk_gb', 0)
|
|
||||||
|
|
||||||
LOG.debug("EventType=%(event_type)s -> host %(host)s: "
|
|
||||||
"ram %(free_ram_mb)d, disk %(free_disk_gb)d, "
|
|
||||||
"work %(work)d, vms%(vms)d" % locals())
|
|
||||||
|
|
||||||
db.api.compute_node_utilization_update(context.get_admin_context(), host,
|
|
||||||
free_ram_mb_delta=free_ram_mb, free_disk_gb_delta=free_disk_gb,
|
|
||||||
work_delta=work, vm_delta=vms)
|
|
||||||
|
|
||||||
return True
|
|
||||||
@@ -1,70 +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 import flags
|
|
||||||
from nova.openstack.common import cfg
|
|
||||||
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.notifier.no_op_notifier'],
|
|
||||||
help='List of drivers to send notifications')
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
|
||||||
FLAGS.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 not drivers:
|
|
||||||
drivers = []
|
|
||||||
for notification_driver in FLAGS.list_notifier_drivers:
|
|
||||||
try:
|
|
||||||
drivers.append(importutils.import_module(notification_driver))
|
|
||||||
except ImportError as e:
|
|
||||||
drivers.append(ImportFailureNotifier(e))
|
|
||||||
return drivers
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,33 +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 import flags
|
|
||||||
from nova.openstack.common import jsonutils
|
|
||||||
from nova.openstack.common import log as logging
|
|
||||||
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
|
||||||
|
|
||||||
|
|
||||||
def notify(_context, message):
|
|
||||||
"""Notifies the recipient of the desired event given the model.
|
|
||||||
Log notifications using nova's default logging system"""
|
|
||||||
|
|
||||||
priority = message.get('priority',
|
|
||||||
FLAGS.default_notification_level)
|
|
||||||
priority = priority.lower()
|
|
||||||
logger = logging.getLogger(
|
|
||||||
'nova.notification.%s' % message['event_type'])
|
|
||||||
getattr(logger, priority)(jsonutils.dumps(message))
|
|
||||||
@@ -1,19 +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.
|
|
||||||
|
|
||||||
|
|
||||||
def notify(_context, message):
|
|
||||||
"""Notifies the recipient of the desired event given the model"""
|
|
||||||
pass
|
|
||||||
@@ -1,47 +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.
|
|
||||||
|
|
||||||
|
|
||||||
import nova.context
|
|
||||||
|
|
||||||
from nova import flags
|
|
||||||
from nova.openstack.common import cfg
|
|
||||||
from nova.openstack.common import log as logging
|
|
||||||
from nova.openstack.common import rpc
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
notification_topic_opt = cfg.ListOpt('notification_topics',
|
|
||||||
default=['notifications', ],
|
|
||||||
help='AMQP topic used for Nova notifications')
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
|
||||||
FLAGS.register_opt(notification_topic_opt)
|
|
||||||
|
|
||||||
|
|
||||||
def notify(context, message):
|
|
||||||
"""Sends a notification to the RabbitMQ"""
|
|
||||||
if not context:
|
|
||||||
context = nova.context.get_admin_context()
|
|
||||||
priority = message.get('priority',
|
|
||||||
FLAGS.default_notification_level)
|
|
||||||
priority = priority.lower()
|
|
||||||
for topic in FLAGS.notification_topics:
|
|
||||||
topic = '%s.%s' % (topic, priority)
|
|
||||||
try:
|
|
||||||
rpc.notify(context, topic, message)
|
|
||||||
except Exception, e:
|
|
||||||
LOG.exception(_("Could not send notification to %(topic)s. "
|
|
||||||
"Payload=%(message)s"), locals())
|
|
||||||
@@ -1,25 +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 import flags
|
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
|
||||||
|
|
||||||
NOTIFICATIONS = []
|
|
||||||
|
|
||||||
|
|
||||||
def notify(_context, message):
|
|
||||||
"""Test notifier, stores notifications in memory for unittests."""
|
|
||||||
NOTIFICATIONS.append(message)
|
|
||||||
@@ -1,16 +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.tests import *
|
|
||||||
@@ -1,59 +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.
|
|
||||||
|
|
||||||
import nova.db.api
|
|
||||||
from nova.notifier import capacity_notifier as cn
|
|
||||||
from nova.openstack.common import jsonutils
|
|
||||||
from nova import test
|
|
||||||
|
|
||||||
|
|
||||||
class CapacityNotifierTestCase(test.TestCase):
|
|
||||||
"""Test case for the Capacity updating notifier."""
|
|
||||||
|
|
||||||
def _make_msg(self, host, event):
|
|
||||||
usage_info = dict(memory_mb=123, disk_gb=456)
|
|
||||||
payload = jsonutils.to_primitive(usage_info, convert_instances=True)
|
|
||||||
return dict(
|
|
||||||
publisher_id="compute.%s" % host,
|
|
||||||
event_type="compute.instance.%s" % event,
|
|
||||||
payload=payload
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_event_type(self):
|
|
||||||
msg = self._make_msg("myhost", "mymethod")
|
|
||||||
msg['event_type'] = 'random'
|
|
||||||
self.assertFalse(cn.notify(None, msg))
|
|
||||||
|
|
||||||
def test_bad_event_suffix(self):
|
|
||||||
msg = self._make_msg("myhost", "mymethod.badsuffix")
|
|
||||||
self.assertFalse(cn.notify(None, msg))
|
|
||||||
|
|
||||||
def test_bad_publisher_id(self):
|
|
||||||
msg = self._make_msg("myhost", "mymethod.start")
|
|
||||||
msg['publisher_id'] = 'badpublisher'
|
|
||||||
self.assertFalse(cn.notify(None, msg))
|
|
||||||
|
|
||||||
def test_update_called(self):
|
|
||||||
def _verify_called(host, context, free_ram_mb_delta,
|
|
||||||
free_disk_gb_delta, work_delta, vm_delta):
|
|
||||||
self.assertEquals(free_ram_mb_delta, 123)
|
|
||||||
self.assertEquals(free_disk_gb_delta, 456)
|
|
||||||
self.assertEquals(vm_delta, -1)
|
|
||||||
self.assertEquals(work_delta, -1)
|
|
||||||
|
|
||||||
self.stubs.Set(nova.db.api, "compute_node_utilization_update",
|
|
||||||
_verify_called)
|
|
||||||
msg = self._make_msg("myhost", "delete.end")
|
|
||||||
self.assertTrue(cn.notify(None, msg))
|
|
||||||
@@ -1,84 +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.
|
|
||||||
|
|
||||||
import nova
|
|
||||||
import nova.notifier.api
|
|
||||||
from nova.notifier import list_notifier
|
|
||||||
import nova.notifier.log_notifier
|
|
||||||
import nova.notifier.no_op_notifier
|
|
||||||
from nova.openstack.common import log as logging
|
|
||||||
from nova import test
|
|
||||||
|
|
||||||
|
|
||||||
class NotifierListTestCase(test.TestCase):
|
|
||||||
"""Test case for notifications"""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(NotifierListTestCase, self).setUp()
|
|
||||||
list_notifier._reset_drivers()
|
|
||||||
# Mock log to add one to exception_count when log.exception is called
|
|
||||||
|
|
||||||
def mock_exception(cls, *args):
|
|
||||||
self.exception_count += 1
|
|
||||||
|
|
||||||
self.exception_count = 0
|
|
||||||
list_notifier_log = logging.getLogger('nova.notifier.list_notifier')
|
|
||||||
self.stubs.Set(list_notifier_log, "exception", mock_exception)
|
|
||||||
# Mock no_op notifier to add one to notify_count when called.
|
|
||||||
|
|
||||||
def mock_notify(cls, *args):
|
|
||||||
self.notify_count += 1
|
|
||||||
|
|
||||||
self.notify_count = 0
|
|
||||||
self.stubs.Set(nova.notifier.no_op_notifier, 'notify', mock_notify)
|
|
||||||
# Mock log_notifier to raise RuntimeError when called.
|
|
||||||
|
|
||||||
def mock_notify2(cls, *args):
|
|
||||||
raise RuntimeError("Bad notifier.")
|
|
||||||
|
|
||||||
self.stubs.Set(nova.notifier.log_notifier, 'notify', mock_notify2)
|
|
||||||
|
|
||||||
def tearDown(self):
|
|
||||||
list_notifier._reset_drivers()
|
|
||||||
super(NotifierListTestCase, self).tearDown()
|
|
||||||
|
|
||||||
def test_send_notifications_successfully(self):
|
|
||||||
self.flags(notification_driver='nova.notifier.list_notifier',
|
|
||||||
list_notifier_drivers=['nova.notifier.no_op_notifier',
|
|
||||||
'nova.notifier.no_op_notifier'])
|
|
||||||
nova.notifier.api.notify('contextarg', 'publisher_id', 'event_type',
|
|
||||||
nova.notifier.api.WARN, dict(a=3))
|
|
||||||
self.assertEqual(self.notify_count, 2)
|
|
||||||
self.assertEqual(self.exception_count, 0)
|
|
||||||
|
|
||||||
def test_send_notifications_with_errors(self):
|
|
||||||
|
|
||||||
self.flags(notification_driver='nova.notifier.list_notifier',
|
|
||||||
list_notifier_drivers=['nova.notifier.no_op_notifier',
|
|
||||||
'nova.notifier.log_notifier'])
|
|
||||||
nova.notifier.api.notify('contextarg', 'publisher_id',
|
|
||||||
'event_type', nova.notifier.api.WARN, dict(a=3))
|
|
||||||
self.assertEqual(self.notify_count, 1)
|
|
||||||
self.assertEqual(self.exception_count, 1)
|
|
||||||
|
|
||||||
def test_when_driver_fails_to_import(self):
|
|
||||||
self.flags(notification_driver='nova.notifier.list_notifier',
|
|
||||||
list_notifier_drivers=['nova.notifier.no_op_notifier',
|
|
||||||
'nova.notifier.logo_notifier',
|
|
||||||
'fdsjgsdfhjkhgsfkj'])
|
|
||||||
nova.notifier.api.notify('contextarg', 'publisher_id',
|
|
||||||
'event_type', nova.notifier.api.WARN, dict(a=3))
|
|
||||||
self.assertEqual(self.exception_count, 2)
|
|
||||||
self.assertEqual(self.notify_count, 1)
|
|
||||||
@@ -22,9 +22,9 @@ from nova.compute import utils as compute_utils
|
|||||||
from nova import context
|
from nova import context
|
||||||
from nova import db
|
from nova import db
|
||||||
from nova import flags
|
from nova import flags
|
||||||
from nova.notifier import test_notifier
|
|
||||||
from nova.openstack.common import importutils
|
from nova.openstack.common import importutils
|
||||||
from nova.openstack.common import log as logging
|
from nova.openstack.common import log as logging
|
||||||
|
from nova.openstack.common.notifier import test_notifier
|
||||||
from nova import test
|
from nova import test
|
||||||
from nova.tests import fake_network
|
from nova.tests import fake_network
|
||||||
import nova.tests.image.fake
|
import nova.tests.image.fake
|
||||||
@@ -50,7 +50,7 @@ class UsageInfoTestCase(test.TestCase):
|
|||||||
|
|
||||||
self.flags(compute_driver='nova.virt.fake.FakeDriver',
|
self.flags(compute_driver='nova.virt.fake.FakeDriver',
|
||||||
stub_network=True,
|
stub_network=True,
|
||||||
notification_driver='nova.notifier.test_notifier',
|
notification_driver='nova.openstack.common.notifier.test_notifier',
|
||||||
network_manager='nova.network.manager.FlatManager')
|
network_manager='nova.network.manager.FlatManager')
|
||||||
self.compute = importutils.import_object(FLAGS.compute_manager)
|
self.compute = importutils.import_object(FLAGS.compute_manager)
|
||||||
self.user_id = 'fake'
|
self.user_id = 'fake'
|
||||||
|
|||||||
@@ -1,184 +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.
|
|
||||||
|
|
||||||
import nova
|
|
||||||
from nova import context
|
|
||||||
from nova import flags
|
|
||||||
from nova.notifier import api as notifier_api
|
|
||||||
import nova.notifier.no_op_notifier
|
|
||||||
from nova.openstack.common import log
|
|
||||||
from nova import test
|
|
||||||
|
|
||||||
|
|
||||||
ctxt = context.get_admin_context()
|
|
||||||
ctxt2 = context.get_admin_context()
|
|
||||||
|
|
||||||
|
|
||||||
class NotifierTestCase(test.TestCase):
|
|
||||||
"""Test case for notifications"""
|
|
||||||
def setUp(self):
|
|
||||||
super(NotifierTestCase, self).setUp()
|
|
||||||
self.flags(notification_driver='nova.notifier.no_op_notifier')
|
|
||||||
|
|
||||||
def test_send_notification(self):
|
|
||||||
self.notify_called = False
|
|
||||||
|
|
||||||
def mock_notify(cls, *args):
|
|
||||||
self.notify_called = True
|
|
||||||
|
|
||||||
self.stubs.Set(nova.notifier.no_op_notifier, 'notify',
|
|
||||||
mock_notify)
|
|
||||||
|
|
||||||
notifier_api.notify(ctxt, 'publisher_id', 'event_type',
|
|
||||||
nova.notifier.api.WARN, dict(a=3))
|
|
||||||
self.assertEqual(self.notify_called, True)
|
|
||||||
|
|
||||||
def test_verify_message_format(self):
|
|
||||||
"""A test to ensure changing the message format is prohibitively
|
|
||||||
annoying"""
|
|
||||||
|
|
||||||
def message_assert(context, message):
|
|
||||||
fields = [('publisher_id', 'publisher_id'),
|
|
||||||
('event_type', 'event_type'),
|
|
||||||
('priority', 'WARN'),
|
|
||||||
('payload', dict(a=3))]
|
|
||||||
for k, v in fields:
|
|
||||||
self.assertEqual(message[k], v)
|
|
||||||
self.assertTrue(len(message['message_id']) > 0)
|
|
||||||
self.assertTrue(len(message['timestamp']) > 0)
|
|
||||||
self.assertEqual(context, ctxt)
|
|
||||||
|
|
||||||
self.stubs.Set(nova.notifier.no_op_notifier, 'notify',
|
|
||||||
message_assert)
|
|
||||||
notifier_api.notify(ctxt, 'publisher_id', 'event_type',
|
|
||||||
nova.notifier.api.WARN, dict(a=3))
|
|
||||||
|
|
||||||
def test_send_rabbit_notification(self):
|
|
||||||
self.stubs.Set(nova.flags.FLAGS, 'notification_driver',
|
|
||||||
'nova.notifier.rabbit_notifier')
|
|
||||||
self.mock_notify = False
|
|
||||||
|
|
||||||
def mock_notify(cls, *args):
|
|
||||||
self.mock_notify = True
|
|
||||||
|
|
||||||
self.stubs.Set(nova.openstack.common.rpc, 'notify', mock_notify)
|
|
||||||
notifier_api.notify(ctxt, 'publisher_id', 'event_type',
|
|
||||||
nova.notifier.api.WARN, dict(a=3))
|
|
||||||
|
|
||||||
self.assertEqual(self.mock_notify, True)
|
|
||||||
|
|
||||||
def test_invalid_priority(self):
|
|
||||||
self.assertRaises(nova.notifier.api.BadPriorityException,
|
|
||||||
notifier_api.notify, ctxt, 'publisher_id',
|
|
||||||
'event_type', 'not a priority', dict(a=3))
|
|
||||||
|
|
||||||
def test_rabbit_priority_queue(self):
|
|
||||||
flags.DECLARE('notification_topics', 'nova.notifier.rabbit_notifier')
|
|
||||||
self.stubs.Set(nova.flags.FLAGS, 'notification_driver',
|
|
||||||
'nova.notifier.rabbit_notifier')
|
|
||||||
self.stubs.Set(nova.flags.FLAGS, 'notification_topics',
|
|
||||||
['testnotify', ])
|
|
||||||
|
|
||||||
self.test_topic = None
|
|
||||||
|
|
||||||
def mock_notify(context, topic, msg):
|
|
||||||
self.test_topic = topic
|
|
||||||
|
|
||||||
self.stubs.Set(nova.openstack.common.rpc, 'notify', mock_notify)
|
|
||||||
notifier_api.notify(ctxt, 'publisher_id',
|
|
||||||
'event_type', 'DEBUG', dict(a=3))
|
|
||||||
self.assertEqual(self.test_topic, 'testnotify.debug')
|
|
||||||
|
|
||||||
def test_error_notification(self):
|
|
||||||
self.stubs.Set(nova.flags.FLAGS, 'notification_driver',
|
|
||||||
'nova.notifier.rabbit_notifier')
|
|
||||||
self.stubs.Set(nova.flags.FLAGS, 'publish_errors', True)
|
|
||||||
LOG = log.getLogger('nova')
|
|
||||||
log.setup('nova')
|
|
||||||
msgs = []
|
|
||||||
|
|
||||||
def mock_notify(context, topic, data):
|
|
||||||
msgs.append(data)
|
|
||||||
|
|
||||||
self.stubs.Set(nova.openstack.common.rpc, 'notify', mock_notify)
|
|
||||||
LOG.error('foo')
|
|
||||||
self.assertEqual(1, len(msgs))
|
|
||||||
msg = msgs[0]
|
|
||||||
self.assertEqual(msg['event_type'], 'error_notification')
|
|
||||||
self.assertEqual(msg['priority'], 'ERROR')
|
|
||||||
self.assertEqual(msg['payload']['error'], 'foo')
|
|
||||||
|
|
||||||
def test_send_notification_by_decorator(self):
|
|
||||||
self.notify_called = False
|
|
||||||
|
|
||||||
def example_api(arg1, arg2):
|
|
||||||
return arg1 + arg2
|
|
||||||
|
|
||||||
example_api = nova.notifier.api.notify_decorator(
|
|
||||||
'example_api',
|
|
||||||
example_api)
|
|
||||||
|
|
||||||
def mock_notify(cls, *args):
|
|
||||||
self.notify_called = True
|
|
||||||
|
|
||||||
self.stubs.Set(nova.notifier.no_op_notifier, 'notify',
|
|
||||||
mock_notify)
|
|
||||||
|
|
||||||
self.assertEqual(3, example_api(1, 2))
|
|
||||||
self.assertEqual(self.notify_called, True)
|
|
||||||
|
|
||||||
def test_decorator_context(self):
|
|
||||||
"""Verify that the notify decorator can extract the 'context' arg."""
|
|
||||||
self.notify_called = False
|
|
||||||
self.context_arg = None
|
|
||||||
|
|
||||||
def example_api(arg1, arg2, context):
|
|
||||||
return arg1 + arg2
|
|
||||||
|
|
||||||
def example_api2(arg1, arg2, **kw):
|
|
||||||
return arg1 + arg2
|
|
||||||
|
|
||||||
example_api = nova.notifier.api.notify_decorator(
|
|
||||||
'example_api',
|
|
||||||
example_api)
|
|
||||||
|
|
||||||
example_api2 = nova.notifier.api.notify_decorator(
|
|
||||||
'example_api2',
|
|
||||||
example_api2)
|
|
||||||
|
|
||||||
def mock_notify(context, cls, _type, _priority, _payload):
|
|
||||||
self.notify_called = True
|
|
||||||
self.context_arg = context
|
|
||||||
|
|
||||||
self.stubs.Set(nova.notifier.api, 'notify',
|
|
||||||
mock_notify)
|
|
||||||
|
|
||||||
# Test positional context
|
|
||||||
self.assertEqual(3, example_api(1, 2, ctxt))
|
|
||||||
self.assertEqual(self.notify_called, True)
|
|
||||||
self.assertEqual(self.context_arg, ctxt)
|
|
||||||
|
|
||||||
self.notify_called = False
|
|
||||||
self.context_arg = None
|
|
||||||
|
|
||||||
# Test named context
|
|
||||||
self.assertEqual(3, example_api2(1, 2, context=ctxt2))
|
|
||||||
self.assertEqual(self.notify_called, True)
|
|
||||||
self.assertEqual(self.context_arg, ctxt2)
|
|
||||||
|
|
||||||
# Test missing context
|
|
||||||
self.assertEqual(3, example_api2(1, 2, bananas="delicious"))
|
|
||||||
self.assertEqual(self.notify_called, True)
|
|
||||||
self.assertEqual(self.context_arg, None)
|
|
||||||
@@ -28,9 +28,9 @@ from nova import context
|
|||||||
from nova import db
|
from nova import db
|
||||||
from nova import exception
|
from nova import exception
|
||||||
from nova import flags
|
from nova import flags
|
||||||
from nova.notifier import test_notifier
|
|
||||||
from nova.openstack.common import importutils
|
from nova.openstack.common import importutils
|
||||||
from nova.openstack.common import log as logging
|
from nova.openstack.common import log as logging
|
||||||
|
from nova.openstack.common.notifier import test_notifier
|
||||||
from nova.openstack.common import rpc
|
from nova.openstack.common import rpc
|
||||||
import nova.policy
|
import nova.policy
|
||||||
from nova import quota
|
from nova import quota
|
||||||
@@ -50,7 +50,7 @@ class VolumeTestCase(test.TestCase):
|
|||||||
self.compute = importutils.import_object(FLAGS.compute_manager)
|
self.compute = importutils.import_object(FLAGS.compute_manager)
|
||||||
self.flags(compute_driver='nova.virt.fake.FakeDriver')
|
self.flags(compute_driver='nova.virt.fake.FakeDriver')
|
||||||
self.stubs.Set(nova.flags.FLAGS, 'notification_driver',
|
self.stubs.Set(nova.flags.FLAGS, 'notification_driver',
|
||||||
'nova.notifier.test_notifier')
|
'nova.openstack.common.notifier.test_notifier')
|
||||||
self.volume = importutils.import_object(FLAGS.volume_manager)
|
self.volume = importutils.import_object(FLAGS.volume_manager)
|
||||||
self.context = context.get_admin_context()
|
self.context = context.get_admin_context()
|
||||||
instance = db.instance_create(self.context, {})
|
instance = db.instance_create(self.context, {})
|
||||||
|
|||||||
@@ -20,9 +20,9 @@
|
|||||||
from nova import context
|
from nova import context
|
||||||
from nova import db
|
from nova import db
|
||||||
from nova import flags
|
from nova import flags
|
||||||
from nova.notifier import test_notifier
|
|
||||||
from nova.openstack.common import importutils
|
from nova.openstack.common import importutils
|
||||||
from nova.openstack.common import log as logging
|
from nova.openstack.common import log as logging
|
||||||
|
from nova.openstack.common.notifier import test_notifier
|
||||||
from nova import test
|
from nova import test
|
||||||
from nova.volume import utils as volume_utils
|
from nova.volume import utils as volume_utils
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ class UsageInfoTestCase(test.TestCase):
|
|||||||
stub_network=True,
|
stub_network=True,
|
||||||
host='fake')
|
host='fake')
|
||||||
self.stubs.Set(flags.FLAGS, 'notification_driver',
|
self.stubs.Set(flags.FLAGS, 'notification_driver',
|
||||||
'nova.notifier.test_notifier')
|
'nova.openstack.common.notifier.test_notifier')
|
||||||
self.volume = importutils.import_object(FLAGS.volume_manager)
|
self.volume = importutils.import_object(FLAGS.volume_manager)
|
||||||
self.user_id = 'fake'
|
self.user_id = 'fake'
|
||||||
self.project_id = 'fake'
|
self.project_id = 'fake'
|
||||||
|
|||||||
Reference in New Issue
Block a user