From 60a91f475a352e5e86bbd07b510cb32874110fef Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Thu, 29 Aug 2013 22:38:31 +0100 Subject: [PATCH] Port to oslo.messaging.Notifier API Add a temporary nova.notifier.Notifier helper class which translates oslo.messaging.Notifier compatible calls into openstack.common.notifier compatible calls. This allows us to port the notifier code over to the oslo.messaging API before actually switching over oslo.messaging fully. This patch contains no functional changes at all, except that all notifications go through this temporary helper class. Some notes on the new API: * The notifier API is changed so that what was previously global state is now encapsulated in a Notifier object. This object also includes the publisher_id and has error()/info()/etc. methods rather than just notify(). * The notify_decorator() helper wasn't carried across to the new API because its semantics are a bit weird. Something along these lines could be added in future, though. * We use a fake Notifier implementation for tests because there's no API in oslo.messaging to actually get the notifications queued up in the fake notification driver, which is a bit dumb. However, this feels like the right thing to do anyway. We're not wanting to test oslo.messaging.Notifier itself, but rather we want to test how we call it. blueprint: oslo-messaging Change-Id: I262163c7e05e6a6fb79265e904ce761fc3ac5806 --- etc/nova/nova.conf.sample | 2 +- nova/compute/api.py | 15 +- nova/compute/manager.py | 20 +- nova/compute/utils.py | 34 +- nova/conductor/manager.py | 9 +- nova/exception.py | 25 +- nova/manager.py | 2 + nova/network/floating_ips.py | 26 +- nova/notifications.py | 49 ++- nova/notifier.py | 73 +++++ nova/scheduler/driver.py | 6 +- nova/scheduler/filter_scheduler.py | 14 +- nova/scheduler/utils.py | 9 +- nova/tests/compute/test_compute.py | 311 +++++++++---------- nova/tests/compute/test_compute_api.py | 4 +- nova/tests/compute/test_compute_utils.py | 85 ++--- nova/tests/conductor/test_conductor.py | 27 +- nova/tests/fake_notifier.py | 53 ++++ nova/tests/scheduler/test_scheduler.py | 22 +- nova/tests/scheduler/test_scheduler_utils.py | 18 +- nova/tests/test_exception.py | 20 +- nova/tests/test_notifications.py | 84 +++-- nova/utils.py | 6 +- nova/virt/libvirt/driver.py | 11 +- 24 files changed, 536 insertions(+), 389 deletions(-) create mode 100644 nova/notifier.py create mode 100644 nova/tests/fake_notifier.py diff --git a/etc/nova/nova.conf.sample b/etc/nova/nova.conf.sample index 776ec14dc822..13425f172060 100644 --- a/etc/nova/nova.conf.sample +++ b/etc/nova/nova.conf.sample @@ -260,7 +260,7 @@ #monkey_patch=false # List of modules/decorators to monkey patch (list value) -#monkey_patch_modules=nova.api.ec2.cloud:nova.openstack.common.notifier.api.notify_decorator,nova.compute.api:nova.openstack.common.notifier.api.notify_decorator +#monkey_patch_modules=nova.api.ec2.cloud:nova.notifications.notify_decorator,nova.compute.api:nova.notifications.notify_decorator # Length of generated instance admin passwords (integer value) #password_length=12 diff --git a/nova/compute/api.py b/nova/compute/api.py index e2ad1fe92309..9a7f6373a95e 100644 --- a/nova/compute/api.py +++ b/nova/compute/api.py @@ -50,6 +50,7 @@ from nova.network import model as network_model from nova.network.security_group import openstack_driver from nova.network.security_group import security_group_base from nova import notifications +from nova import notifier from nova.objects import aggregate as aggregate_obj from nova.objects import base as obj_base from nova.objects import instance as instance_obj @@ -62,7 +63,6 @@ from nova.objects import service as service_obj from nova.openstack.common import excutils from nova.openstack.common.gettextutils import _ from nova.openstack.common import log as logging -from nova.openstack.common.notifier import api as notifier from nova.openstack.common import strutils from nova.openstack.common import timeutils from nova.openstack.common import uuidutils @@ -75,11 +75,9 @@ from nova import volume LOG = logging.getLogger(__name__) - -wrap_exception = functools.partial( - exception.wrap_exception, - notifier=notifier, publisher_id=notifier.publisher_id('aggregate')) - +get_notifier = functools.partial(notifier.get_notifier, service='aggregate') +wrap_exception = functools.partial(exception.wrap_exception, + get_notifier=get_notifier) compute_opts = [ cfg.BoolOpt('allow_resize_to_same_host', @@ -236,6 +234,7 @@ class API(base.Base): self.compute_rpcapi = compute_rpcapi.ComputeAPI() self._compute_task_api = None self.servicegroup_api = servicegroup.API() + self.notifier = notifier.get_notifier('compute', CONF.host) super(API, self).__init__(**kwargs) @@ -1418,7 +1417,7 @@ class API(base.Base): instance_uuid = instance['uuid'] instance.info_cache.delete() compute_utils.notify_about_instance_usage( - context, instance, "%s.start" % delete_type) + self.notifier, context, instance, "%s.start" % delete_type) elevated = context.elevated() if self.cell_type != 'api': @@ -1445,7 +1444,7 @@ class API(base.Base): cb(context, instance, bdms, local=True) instance.destroy() compute_utils.notify_about_instance_usage( - context, instance, "%s.end" % delete_type, + self.notifier, context, instance, "%s.end" % delete_type, system_metadata=system_meta) def _do_delete(self, context, instance, bdms, reservations=None, diff --git a/nova/compute/manager.py b/nova/compute/manager.py index 9c9e307e8924..722f90f38c09 100755 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -60,6 +60,7 @@ from nova import manager from nova import network from nova.network import model as network_model from nova.network.security_group import openstack_driver +from nova import notifier from nova.objects import base as obj_base from nova.objects import instance as instance_obj from nova.objects import migration as migration_obj @@ -67,7 +68,6 @@ from nova.openstack.common import excutils from nova.openstack.common.gettextutils import _ from nova.openstack.common import jsonutils from nova.openstack.common import log as logging -from nova.openstack.common.notifier import api as notifier from nova.openstack.common import periodic_task from nova.openstack.common import rpc from nova.openstack.common.rpc import common as rpc_common @@ -214,10 +214,9 @@ CONF.import_opt('enable', 'nova.cells.opts', group='cells') LOG = logging.getLogger(__name__) - -wrap_exception = functools.partial( - exception.wrap_exception, - notifier=notifier, publisher_id=notifier.publisher_id('compute')) +get_notifier = functools.partial(notifier.get_notifier, service='compute') +wrap_exception = functools.partial(exception.wrap_exception, + get_notifier=get_notifier) def reverts_task_state(function): @@ -1364,14 +1363,11 @@ class ComputeManager(manager.SchedulerDependentManager): def _notify_about_instance_usage(self, context, instance, event_suffix, network_info=None, system_metadata=None, extra_usage_info=None): - # NOTE(sirp): The only thing this wrapper function does extra is handle - # the passing in of `self.host`. Ordinarily this will just be - # CONF.host`, but `Manager`'s gets a chance to override this in its - # `__init__`. compute_utils.notify_about_instance_usage( - context, instance, event_suffix, network_info=network_info, - system_metadata=system_metadata, - extra_usage_info=extra_usage_info, host=self.host) + self.notifier, context, instance, event_suffix, + network_info=network_info, + system_metadata=system_metadata, + extra_usage_info=extra_usage_info) def _deallocate_network(self, context, instance, requested_networks=None): diff --git a/nova/compute/utils.py b/nova/compute/utils.py index fb2ab6d2007d..f63da1b66161 100644 --- a/nova/compute/utils.py +++ b/nova/compute/utils.py @@ -27,10 +27,10 @@ from nova.compute import flavors from nova import exception from nova.network import model as network_model from nova import notifications +from nova import notifier as notify from nova.objects import instance as instance_obj from nova.openstack.common.gettextutils import _ from nova.openstack.common import log -from nova.openstack.common.notifier import api as notifier_api from nova.openstack.common import timeutils from nova import utils from nova.virt import driver @@ -191,12 +191,14 @@ def _get_unused_letter(used_letters): return letters[0] -def notify_usage_exists(context, instance_ref, current_period=False, +def notify_usage_exists(notifier, context, instance_ref, current_period=False, ignore_missing_network_data=True, system_metadata=None, extra_usage_info=None): """Generates 'exists' notification for an instance for usage auditing purposes. + :param notifier: a messaging.Notifier + :param current_period: if True, this will generate a usage for the current usage period; if False, this will generate a usage for the previous audit period. @@ -228,29 +230,24 @@ def notify_usage_exists(context, instance_ref, current_period=False, if extra_usage_info: extra_info.update(extra_usage_info) - notify_about_instance_usage(context, instance_ref, 'exists', + notify_about_instance_usage(notifier, context, instance_ref, 'exists', system_metadata=system_metadata, extra_usage_info=extra_info) -def notify_about_instance_usage(context, instance, event_suffix, +def notify_about_instance_usage(notifier, context, instance, event_suffix, network_info=None, system_metadata=None, - extra_usage_info=None, host=None): + extra_usage_info=None): """ Send a notification about an instance. + :param notifier: a messaging.Notifier :param event_suffix: Event type like "delete.start" or "exists" :param network_info: Networking information, if provided. :param system_metadata: system_metadata DB entries for the instance, if provided. :param extra_usage_info: Dictionary containing extra values to add or override in the notification. - :param host: Compute host for the instance, if specified. Default is - CONF.host """ - - if not host: - host = CONF.host - if not extra_usage_info: extra_usage_info = {} @@ -258,13 +255,11 @@ def notify_about_instance_usage(context, instance, event_suffix, network_info, system_metadata, **extra_usage_info) if event_suffix.endswith("error"): - level = notifier_api.ERROR + method = notifier.error else: - level = notifier_api.INFO + method = notifier.info - notifier_api.notify(context, 'compute.%s' % host, - 'compute.instance.%s' % event_suffix, level, - usage_info) + method(context, 'compute.instance.%s' % event_suffix, usage_info) def notify_about_aggregate_update(context, event_suffix, aggregate_payload): @@ -282,9 +277,10 @@ def notify_about_aggregate_update(context, event_suffix, aggregate_payload): "notification and it will be ignored")) return - notifier_api.notify(context, 'aggregate.%s' % aggregate_identifier, - 'aggregate.%s' % event_suffix, notifier_api.INFO, - aggregate_payload) + notifier = notify.get_notifier(service='aggregate', + host=aggregate_identifier) + + notifier.info(context, 'aggregate.%s' % event_suffix, aggregate_payload) def get_nw_info_for_instance(instance): diff --git a/nova/conductor/manager.py b/nova/conductor/manager.py index 5badd443c9aa..e2dab2803c2a 100644 --- a/nova/conductor/manager.py +++ b/nova/conductor/manager.py @@ -39,7 +39,6 @@ from nova.openstack.common import excutils from nova.openstack.common.gettextutils import _ from nova.openstack.common import jsonutils from nova.openstack.common import log as logging -from nova.openstack.common.notifier import api as notifier from nova.openstack.common.rpc import common as rpc_common from nova.openstack.common import timeutils from nova import quota @@ -401,9 +400,8 @@ class ConductorManager(manager.Manager): update_totals) # We have just updated the database, so send the notification now - notifier.notify(context, 'conductor.%s' % self.host, 'volume.usage', - notifier.INFO, - compute_utils.usage_volume_info(vol_usage)) + self.notifier.info(context, 'volume.usage', + compute_utils.usage_volume_info(vol_usage)) @rpc_common.client_exceptions(exception.ComputeHostNotFound, exception.HostBinaryNotFound) @@ -482,7 +480,8 @@ class ConductorManager(manager.Manager): def notify_usage_exists(self, context, instance, current_period=False, ignore_missing_network_data=True, system_metadata=None, extra_usage_info=None): - compute_utils.notify_usage_exists(context, instance, current_period, + compute_utils.notify_usage_exists(self.notifier, context, instance, + current_period, ignore_missing_network_data, system_metadata, extra_usage_info) diff --git a/nova/exception.py b/nova/exception.py index 04fdec112bed..07917b37ddc7 100644 --- a/nova/exception.py +++ b/nova/exception.py @@ -60,14 +60,11 @@ def _cleanse_dict(original): return dict((k, v) for k, v in original.iteritems() if not "_pass" in k) -def wrap_exception(notifier, publisher_id): +def wrap_exception(notifier=None, get_notifier=None): """This decorator wraps a method to catch any exceptions that may get thrown. It logs the exception as well as optionally sending it to the notification system. """ - # TODO(sandy): Find a way to import nova.notifier.api so we don't have - # to pass it in as a parameter. Otherwise we get a cyclic import of - # nova.notifier.api -> nova.utils -> nova.exception :( def inner(f): def wrapped(self, context, *args, **kw): # Don't store self or context in the payload, it now seems to @@ -76,16 +73,20 @@ def wrap_exception(notifier, publisher_id): return f(self, context, *args, **kw) except Exception as e: with excutils.save_and_reraise_exception(): - payload = dict(exception=e) - call_dict = safe_utils.getcallargs(f, *args, **kw) - cleansed = _cleanse_dict(call_dict) - payload.update({'args': cleansed}) + if notifier or get_notifier: + payload = dict(exception=e) + call_dict = safe_utils.getcallargs(f, *args, **kw) + cleansed = _cleanse_dict(call_dict) + payload.update({'args': cleansed}) - level = notifier.ERROR - event_type = f.__name__ + # If f has multiple decorators, they must use + # functools.wraps to ensure the name is + # propagated. + event_type = f.__name__ - notifier.notify(context, publisher_id, - event_type, level, payload) + (notifier or get_notifier()).error(context, + event_type, + payload) return functools.wraps(f)(wrapped) return inner diff --git a/nova/manager.py b/nova/manager.py index a270b927b7de..68c8f9449d12 100644 --- a/nova/manager.py +++ b/nova/manager.py @@ -57,6 +57,7 @@ from oslo.config import cfg from nova import baserpc from nova.db import base +from nova import notifier from nova.objects import base as objects_base from nova.openstack.common.gettextutils import _ from nova.openstack.common import log as logging @@ -80,6 +81,7 @@ class Manager(base.Base, periodic_task.PeriodicTasks): self.host = host self.backdoor_port = None self.service_name = service_name + self.notifier = notifier.get_notifier(self.service_name, self.host) super(Manager, self).__init__(db_driver) def create_rpc_dispatcher(self, backdoor_port=None, additional_apis=None): diff --git a/nova/network/floating_ips.py b/nova/network/floating_ips.py index b5e4aecc0706..2fbaa0647d44 100644 --- a/nova/network/floating_ips.py +++ b/nova/network/floating_ips.py @@ -23,11 +23,11 @@ from nova import context from nova.db import base from nova import exception from nova.network import rpcapi as network_rpcapi +from nova import notifier from nova.openstack.common import excutils from nova.openstack.common.gettextutils import _ from nova.openstack.common import importutils from nova.openstack.common import log as logging -from nova.openstack.common.notifier import api as notifier from nova.openstack.common import processutils from nova.openstack.common.rpc import common as rpc_common from nova.openstack.common import uuidutils @@ -224,10 +224,8 @@ class FloatingIP(object): floating_ip = self.db.floating_ip_allocate_address( context, project_id, pool, auto_assigned=auto_assigned) payload = dict(project_id=project_id, floating_ip=floating_ip) - notifier.notify(context, - notifier.publisher_id("network"), - 'network.floating_ip.allocate', - notifier.INFO, payload) + self.notifier.info(context, + 'network.floating_ip.allocate', payload) # Commit the reservations if use_quota: @@ -263,10 +261,7 @@ class FloatingIP(object): floating_ip['address']) payload = dict(project_id=floating_ip['project_id'], floating_ip=floating_ip['address']) - notifier.notify(context, - notifier.publisher_id("network"), - 'network.floating_ip.deallocate', - notifier.INFO, payload=payload) + self.notifier.info(context, 'network.floating_ip.deallocate', payload) # Get reservations... try: @@ -375,10 +370,8 @@ class FloatingIP(object): payload = dict(project_id=context.project_id, instance_id=instance_uuid, floating_ip=floating_address) - notifier.notify(context, - notifier.publisher_id("network"), - 'network.floating_ip.associate', - notifier.INFO, payload=payload) + self.notifier.info(context, + 'network.floating_ip.associate', payload) do_associate() @rpc_common.client_exceptions(exception.FloatingIpNotFoundForAddress) @@ -461,10 +454,8 @@ class FloatingIP(object): payload = dict(project_id=context.project_id, instance_id=instance_uuid, floating_ip=address) - notifier.notify(context, - notifier.publisher_id("network"), - 'network.floating_ip.disassociate', - notifier.INFO, payload=payload) + self.notifier.info(context, + 'network.floating_ip.disassociate', payload) do_disassociate() @rpc_common.client_exceptions(exception.FloatingIpNotFound) @@ -699,3 +690,4 @@ class LocalManager(base.Base, FloatingIP): CONF.floating_ip_dns_manager) self.instance_dns_manager = importutils.import_object( CONF.instance_dns_manager) + self.notifier = notifier.get_notifier('network', CONF.host) diff --git a/nova/notifications.py b/nova/notifications.py index aefd1fa82a4b..fe0dd73904e8 100644 --- a/nova/notifications.py +++ b/nova/notifications.py @@ -2,6 +2,7 @@ # Copyright (c) 2012 OpenStack Foundation # All Rights Reserved. +# Copyright 2013 Red Hat, Inc. # # 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 @@ -29,10 +30,11 @@ from nova import db from nova.image import glance from nova import network from nova.network import model as network_model +from nova import notifier as notify +from nova.openstack.common import context as common_context from nova.openstack.common import excutils from nova.openstack.common.gettextutils import _ from nova.openstack.common import log -from nova.openstack.common.notifier import api as notifier_api from nova.openstack.common import timeutils from nova import utils @@ -53,6 +55,40 @@ notify_opts = [ CONF = cfg.CONF CONF.register_opts(notify_opts) +CONF.import_opt('default_notification_level', + 'nova.openstack.common.notifier.api') +CONF.import_opt('default_publisher_id', + 'nova.openstack.common.notifier.api') + + +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] + + ctxt = common_context.get_context_from_function_and_args( + fn, args, kwarg) + + notifier = notify.get_notifier(publisher_id=(CONF.default_publisher_id + or CONF.host)) + method = notifier.getattr(CONF.default_notification_level.lower(), + 'info') + method(ctxt, name, body) + + return fn(*args, **kwarg) + return wrapped_func def send_api_fault(url, status, exception): @@ -63,10 +99,7 @@ def send_api_fault(url, status, exception): payload = {'url': url, 'exception': str(exception), 'status': status} - publisher_id = notifier_api.publisher_id("api") - - notifier_api.notify(None, publisher_id, 'api.fault', notifier_api.ERROR, - payload) + notify.get_notifier('api').error(None, 'api.fault', payload) def send_update(context, old_instance, new_instance, service=None, host=None): @@ -192,10 +225,8 @@ def _send_instance_update_notification(context, instance, old_vm_state=None, if old_display_name: payload["old_display_name"] = old_display_name - publisher_id = notifier_api.publisher_id(service, host) - - notifier_api.notify(context, publisher_id, 'compute.instance.update', - notifier_api.INFO, payload) + notify.get_notifier(service, host).info(context, + 'compute.instance.update', payload) def audit_period_bounds(current_period=False): diff --git a/nova/notifier.py b/nova/notifier.py new file mode 100644 index 000000000000..165dcaa084b9 --- /dev/null +++ b/nova/notifier.py @@ -0,0 +1,73 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Red Hat, Inc. +# +# 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. + +""" +A temporary helper which emulates oslo.messaging.Notifier. + +This helper method allows us to do the tedious porting to the new Notifier API +as a standalone commit so that the commit which switches us to oslo.messaging +is smaller and easier to review. This file will be removed as part of that +commit. +""" + +from oslo.config import cfg + +from nova.openstack.common.notifier import api as notifier_api + +CONF = cfg.CONF + + +class Notifier(object): + + def __init__(self, publisher_id): + super(Notifier, self).__init__() + self.publisher_id = publisher_id + + _marker = object() + + def prepare(self, publisher_id=_marker): + ret = self.__class__(self.publisher_id) + if publisher_id is not self._marker: + ret.publisher_id = publisher_id + return ret + + def _notify(self, ctxt, event_type, payload, priority): + notifier_api.notify(ctxt, + self.publisher_id, + event_type, + priority, + payload) + + def debug(self, ctxt, event_type, payload): + self._notify(ctxt, event_type, payload, 'DEBUG') + + def info(self, ctxt, event_type, payload): + self._notify(ctxt, event_type, payload, 'INFO') + + def warn(self, ctxt, event_type, payload): + self._notify(ctxt, event_type, payload, 'WARN') + + def error(self, ctxt, event_type, payload): + self._notify(ctxt, event_type, payload, 'ERROR') + + def critical(self, ctxt, event_type, payload): + self._notify(ctxt, event_type, payload, 'CRITICAL') + + +def get_notifier(service=None, host=None, publisher_id=None): + if not publisher_id: + publisher_id = "%s.%s" % (service, host or CONF.host) + return Notifier(publisher_id) diff --git a/nova/scheduler/driver.py b/nova/scheduler/driver.py index 87ac3f5dad6c..e86db9d1393a 100644 --- a/nova/scheduler/driver.py +++ b/nova/scheduler/driver.py @@ -31,10 +31,10 @@ from nova.conductor import api as conductor_api from nova import db from nova import exception from nova import notifications +from nova import notifier from nova.openstack.common.gettextutils import _ from nova.openstack.common import importutils from nova.openstack.common import log as logging -from nova.openstack.common.notifier import api as notifier from nova.openstack.common import timeutils from nova import servicegroup @@ -78,8 +78,8 @@ def handle_schedule_error(context, ex, instance_uuid, request_spec): method='run_instance', reason=ex) - notifier.notify(context, notifier.publisher_id("scheduler"), - 'scheduler.run_instance', notifier.ERROR, payload) + notifier.get_notifier('scheduler').error(context, + 'scheduler.run_instance', payload) def instance_update_db(context, instance_uuid, extra_values=None): diff --git a/nova/scheduler/filter_scheduler.py b/nova/scheduler/filter_scheduler.py index f9c15c106a92..d5f2848efdbd 100644 --- a/nova/scheduler/filter_scheduler.py +++ b/nova/scheduler/filter_scheduler.py @@ -27,9 +27,9 @@ from nova.compute import flavors from nova.compute import rpcapi as compute_rpcapi from nova import db from nova import exception +from nova import notifier from nova.openstack.common.gettextutils import _ from nova.openstack.common import log as logging -from nova.openstack.common.notifier import api as notifier from nova.pci import pci_request from nova.scheduler import driver from nova.scheduler import scheduler_options @@ -61,6 +61,7 @@ class FilterScheduler(driver.Scheduler): super(FilterScheduler, self).__init__(*args, **kwargs) self.options = scheduler_options.SchedulerOptions() self.compute_rpcapi = compute_rpcapi.ComputeAPI() + self.notifier = notifier.get_notifier('scheduler') def schedule_run_instance(self, context, request_spec, admin_password, injected_files, @@ -73,8 +74,7 @@ class FilterScheduler(driver.Scheduler): Returns a list of the instances created. """ payload = dict(request_spec=request_spec) - notifier.notify(context, notifier.publisher_id("scheduler"), - 'scheduler.run_instance.start', notifier.INFO, payload) + self.notifier.info(context, 'scheduler.run_instance.start', payload) instance_uuids = request_spec.get('instance_uuids') LOG.info(_("Attempting to build %(num_instances)d instance(s) " @@ -127,8 +127,7 @@ class FilterScheduler(driver.Scheduler): retry = filter_properties.get('retry', {}) retry['hosts'] = [] - notifier.notify(context, notifier.publisher_id("scheduler"), - 'scheduler.run_instance.end', notifier.INFO, payload) + self.notifier.info(context, 'scheduler.run_instance.end', payload) def select_hosts(self, context, request_spec, filter_properties): """Selects a filtered set of hosts.""" @@ -164,9 +163,8 @@ class FilterScheduler(driver.Scheduler): payload = dict(request_spec=request_spec, weighted_host=weighed_host.to_dict(), instance_id=instance_uuid) - notifier.notify(context, notifier.publisher_id("scheduler"), - 'scheduler.run_instance.scheduled', notifier.INFO, - payload) + self.notifier.info(context, + 'scheduler.run_instance.scheduled', payload) # Update the metadata if necessary scheduler_hints = filter_properties.get('scheduler_hints') or {} diff --git a/nova/scheduler/utils.py b/nova/scheduler/utils.py index 1a436d30720b..93aec54b1596 100644 --- a/nova/scheduler/utils.py +++ b/nova/scheduler/utils.py @@ -20,10 +20,10 @@ from nova.compute import flavors from nova.compute import utils as compute_utils from nova import db from nova import notifications +from nova import notifier as notify from nova.openstack.common.gettextutils import _ from nova.openstack.common import jsonutils from nova.openstack.common import log as logging -from nova.openstack.common.notifier import api as notifier LOG = logging.getLogger(__name__) @@ -69,6 +69,8 @@ def set_vm_state_and_notify(context, service, method, updates, ex, # verify that uuid is always set. uuids = [properties.get('uuid')] from nova.conductor import api as conductor_api + conductor = conductor_api.LocalAPI() + notifier = notify.get_notifier(service) for instance_uuid in request_spec.get('instance_uuids') or uuids: if instance_uuid: state = vm_state.upper() @@ -81,7 +83,7 @@ def set_vm_state_and_notify(context, service, method, updates, ex, notifications.send_update(context, old_ref, new_ref, service=service) compute_utils.add_instance_fault_from_exc(context, - conductor_api.LocalAPI(), + conductor, new_ref, ex, sys.exc_info()) payload = dict(request_spec=request_spec, @@ -92,8 +94,7 @@ def set_vm_state_and_notify(context, service, method, updates, ex, reason=ex) event_type = '%s.%s' % (service, method) - notifier.notify(context, notifier.publisher_id(service), - event_type, notifier.ERROR, payload) + notifier.error(context, event_type, payload) def populate_filter_properties(filter_properties, host_state): diff --git a/nova/tests/compute/test_compute.py b/nova/tests/compute/test_compute.py index f2d1ae185191..2b4c2cf4d991 100644 --- a/nova/tests/compute/test_compute.py +++ b/nova/tests/compute/test_compute.py @@ -4,6 +4,7 @@ # Administrator of the National Aeronautics and Space Administration. # Copyright 2011 Piston Cloud Computing, Inc. # All Rights Reserved. +# Copyright 2013 Red Hat, Inc. # # 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 @@ -60,8 +61,6 @@ from nova.openstack.common.gettextutils import _ 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 rpc from nova.openstack.common.rpc import common as rpc_common from nova.openstack.common import timeutils @@ -75,6 +74,7 @@ from nova.tests import fake_instance from nova.tests import fake_instance_actions from nova.tests import fake_network from nova.tests import fake_network_cache_model +from nova.tests import fake_notifier from nova.tests.image import fake as fake_image from nova.tests import matchers from nova.tests.objects import test_migration @@ -147,13 +147,14 @@ class BaseTestCase(test.TestCase): def setUp(self): super(BaseTestCase, self).setUp() - notifier_api._reset_drivers() - self.addCleanup(notifier_api._reset_drivers) self.flags(compute_driver='nova.virt.fake.FakeDriver', - notification_driver=[test_notifier.__name__], network_manager='nova.network.manager.FlatManager') fake.set_nodes([NODENAME]) self.flags(use_local=True, group='conductor') + + fake_notifier.stub_notifier(self.stubs) + self.addCleanup(fake_notifier.reset) + self.compute = importutils.import_object(CONF.compute_manager) # override tracker with a version that doesn't need the database: @@ -201,7 +202,6 @@ class BaseTestCase(test.TestCase): self.project_id = 'fake' self.context = context.RequestContext(self.user_id, self.project_id) - test_notifier.NOTIFICATIONS = [] def fake_show(meh, context, id): if id: @@ -581,19 +581,18 @@ class ComputeVolumeTestCase(BaseTestCase): CONF.volume_usage_poll_interval = 10 self.compute._poll_volume_usage(self.context) # Check that a volume.usage and volume.attach notification was sent - self.assertEqual(2, len(test_notifier.NOTIFICATIONS)) - msg = test_notifier.NOTIFICATIONS[0] + self.assertEqual(2, len(fake_notifier.NOTIFICATIONS)) self.compute.detach_volume(self.context, 1, instance) # Check that volume.attach, 2 volume.usage, and volume.detach # notifications were sent - self.assertEquals(4, len(test_notifier.NOTIFICATIONS)) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals('compute.instance.volume.attach', msg['event_type']) - msg = test_notifier.NOTIFICATIONS[2] - self.assertEquals('volume.usage', msg['event_type']) - payload = msg['payload'] + self.assertEquals(4, len(fake_notifier.NOTIFICATIONS)) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEquals('compute.instance.volume.attach', msg.event_type) + msg = fake_notifier.NOTIFICATIONS[2] + self.assertEquals('volume.usage', msg.event_type) + payload = msg.payload self.assertEquals(instance['uuid'], payload['instance_id']) self.assertEquals('fake', payload['user_id']) self.assertEquals('fake', payload['tenant_id']) @@ -602,8 +601,8 @@ class ComputeVolumeTestCase(BaseTestCase): self.assertEquals(1, payload['writes']) self.assertEquals(20, payload['write_bytes']) self.assertEquals(None, payload['availability_zone']) - msg = test_notifier.NOTIFICATIONS[3] - self.assertEquals('compute.instance.volume.detach', msg['event_type']) + msg = fake_notifier.NOTIFICATIONS[3] + self.assertEquals('compute.instance.volume.detach', msg.event_type) # Check the database for the volume_usages = db.vol_get_usage_by_time(self.context, 0) @@ -2601,11 +2600,11 @@ class ComputeTestCase(BaseTestCase): instance = jsonutils.to_primitive(self._create_fake_instance()) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 0) + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 0) self.compute.add_fixed_ip_to_instance(self.context, network_id=1, instance=instance) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 2) + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 2) self.compute.terminate_instance(self.context, instance=instance) def test_remove_fixed_ip_usage_notification(self): @@ -2621,11 +2620,11 @@ class ComputeTestCase(BaseTestCase): instance = jsonutils.to_primitive(self._create_fake_instance()) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 0) + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 0) self.compute.remove_fixed_ip_from_instance(self.context, 1, instance=instance) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 2) + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 2) self.compute.terminate_instance(self.context, instance=instance) def test_run_instance_usage_notification(self): @@ -2633,16 +2632,16 @@ class ComputeTestCase(BaseTestCase): instance = jsonutils.to_primitive(self._create_fake_instance()) instance_uuid = instance['uuid'] self.compute.run_instance(self.context, instance=instance) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 2) + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 2) inst_ref = db.instance_get_by_uuid(self.context, instance_uuid) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals(msg['event_type'], 'compute.instance.create.start') - self.assertEquals(msg['payload']['image_name'], 'fake_name') + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEquals(msg.event_type, 'compute.instance.create.start') + self.assertEquals(msg.payload['image_name'], 'fake_name') # The last event is the one with the sugar in it. - msg = test_notifier.NOTIFICATIONS[1] - self.assertEquals(msg['priority'], 'INFO') - self.assertEquals(msg['event_type'], 'compute.instance.create.end') - payload = msg['payload'] + msg = fake_notifier.NOTIFICATIONS[1] + self.assertEquals(msg.priority, 'INFO') + self.assertEquals(msg.event_type, 'compute.instance.create.end') + payload = msg.payload self.assertEquals(payload['tenant_id'], self.project_id) self.assertEquals(payload['image_name'], 'fake_name') self.assertEquals(payload['user_id'], self.user_id) @@ -2674,14 +2673,14 @@ class ComputeTestCase(BaseTestCase): self.stubs.Set(self.compute, '_build_instance', build_inst_abort) self.compute.run_instance(self.context, instance=instance) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 2) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals(msg['event_type'], 'compute.instance.create.start') - msg = test_notifier.NOTIFICATIONS[1] + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 2) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEquals(msg.event_type, 'compute.instance.create.start') + msg = fake_notifier.NOTIFICATIONS[1] - self.assertEquals(msg['event_type'], 'compute.instance.create.end') - self.assertEquals('INFO', msg['priority']) - payload = msg['payload'] + self.assertEquals(msg.event_type, 'compute.instance.create.end') + self.assertEquals('INFO', msg.priority) + payload = msg.payload message = payload['message'] self.assertTrue(message.find("already deleted") != -1) @@ -2698,14 +2697,14 @@ class ComputeTestCase(BaseTestCase): self.compute.run_instance(self.context, instance=instance) - self.assertTrue(len(test_notifier.NOTIFICATIONS) >= 2) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals(msg['event_type'], 'compute.instance.create.start') - msg = test_notifier.NOTIFICATIONS[1] + self.assertTrue(len(fake_notifier.NOTIFICATIONS) >= 2) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEquals(msg.event_type, 'compute.instance.create.start') + msg = fake_notifier.NOTIFICATIONS[1] - self.assertEquals(msg['event_type'], 'compute.instance.create.error') - self.assertEquals('ERROR', msg['priority']) - payload = msg['payload'] + self.assertEquals(msg.event_type, 'compute.instance.create.error') + self.assertEquals('ERROR', msg.priority) + payload = msg.payload message = payload['message'] self.assertTrue(message.find("something bad happened") != -1) @@ -2722,14 +2721,14 @@ class ComputeTestCase(BaseTestCase): self.assertRaises(test.TestingException, self.compute.run_instance, self.context, instance=instance) - self.assertTrue(len(test_notifier.NOTIFICATIONS) >= 2) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals(msg['event_type'], 'compute.instance.create.start') - msg = test_notifier.NOTIFICATIONS[1] + self.assertTrue(len(fake_notifier.NOTIFICATIONS) >= 2) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEquals(msg.event_type, 'compute.instance.create.start') + msg = fake_notifier.NOTIFICATIONS[1] - self.assertEquals(msg['event_type'], 'compute.instance.create.error') - self.assertEquals('ERROR', msg['priority']) - payload = msg['payload'] + self.assertEquals(msg.event_type, 'compute.instance.create.error') + self.assertEquals('ERROR', msg.priority) + payload = msg.payload message = payload['message'] self.assertTrue(message.find("i'm dying") != -1) @@ -2741,23 +2740,22 @@ class ComputeTestCase(BaseTestCase): instance = jsonutils.to_primitive(self._create_fake_instance()) self.compute.run_instance(self.context, instance=instance) - test_notifier.NOTIFICATIONS = [] + fake_notifier.NOTIFICATIONS = [] timeutils.set_time_override(cur_time) self.compute.terminate_instance(self.context, instance=instance) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 4) + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 4) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals(msg['priority'], 'INFO') - self.assertEquals(msg['event_type'], 'compute.instance.delete.start') - msg1 = test_notifier.NOTIFICATIONS[1] - self.assertEquals(msg1['event_type'], - 'compute.instance.shutdown.start') - msg1 = test_notifier.NOTIFICATIONS[2] - self.assertEquals(msg1['event_type'], 'compute.instance.shutdown.end') - msg1 = test_notifier.NOTIFICATIONS[3] - self.assertEquals(msg1['event_type'], 'compute.instance.delete.end') - payload = msg1['payload'] + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEquals(msg.priority, 'INFO') + self.assertEquals(msg.event_type, 'compute.instance.delete.start') + msg1 = fake_notifier.NOTIFICATIONS[1] + self.assertEquals(msg1.event_type, 'compute.instance.shutdown.start') + msg1 = fake_notifier.NOTIFICATIONS[2] + self.assertEquals(msg1.event_type, 'compute.instance.shutdown.end') + msg1 = fake_notifier.NOTIFICATIONS[3] + self.assertEquals(msg1.event_type, 'compute.instance.delete.end') + payload = msg1.payload self.assertEquals(payload['tenant_id'], self.project_id) self.assertEquals(payload['user_id'], self.user_id) self.assertEquals(payload['instance_id'], instance['uuid']) @@ -3502,7 +3500,7 @@ class ComputeTestCase(BaseTestCase): self.compute.run_instance(self.context, instance=inst_ref) timeutils.set_time_override(cur_time) - test_notifier.NOTIFICATIONS = [] + fake_notifier.NOTIFICATIONS = [] instance = db.instance_get_by_uuid(self.context, inst_ref['uuid']) orig_sys_metadata = db.instance_system_metadata_get(self.context, inst_ref['uuid']) @@ -3530,21 +3528,21 @@ class ComputeTestCase(BaseTestCase): image_ref_url = glance.generate_image_url(image_ref) new_image_ref_url = glance.generate_image_url(new_image_ref) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 3) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals(msg['event_type'], + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 3) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEquals(msg.event_type, 'compute.instance.exists') - self.assertEquals(msg['payload']['image_ref_url'], image_ref_url) - msg = test_notifier.NOTIFICATIONS[1] - self.assertEquals(msg['event_type'], + self.assertEquals(msg.payload['image_ref_url'], image_ref_url) + msg = fake_notifier.NOTIFICATIONS[1] + self.assertEquals(msg.event_type, 'compute.instance.rebuild.start') - self.assertEquals(msg['payload']['image_ref_url'], new_image_ref_url) - self.assertEquals(msg['payload']['image_name'], 'fake_name') - msg = test_notifier.NOTIFICATIONS[2] - self.assertEquals(msg['event_type'], + self.assertEquals(msg.payload['image_ref_url'], new_image_ref_url) + self.assertEquals(msg.payload['image_name'], 'fake_name') + msg = fake_notifier.NOTIFICATIONS[2] + self.assertEquals(msg.event_type, 'compute.instance.rebuild.end') - self.assertEquals(msg['priority'], 'INFO') - payload = msg['payload'] + self.assertEquals(msg.priority, 'INFO') + payload = msg.payload self.assertEquals(payload['image_name'], 'fake_name') self.assertEquals(payload['tenant_id'], self.project_id) self.assertEquals(payload['user_id'], self.user_id) @@ -3587,7 +3585,7 @@ class ComputeTestCase(BaseTestCase): self.compute.resize_instance(self.context, instance=instance, migration=migration, image={}, instance_type=new_type) timeutils.set_time_override(cur_time) - test_notifier.NOTIFICATIONS = [] + fake_notifier.NOTIFICATIONS = [] instance_p = obj_base.obj_to_primitive(instance) migration_p = obj_base.obj_to_primitive(migration) @@ -3595,15 +3593,15 @@ class ComputeTestCase(BaseTestCase): migration=migration_p, disk_info={}, image={}, instance=instance_p) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 2) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals(msg['event_type'], + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 2) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEquals(msg.event_type, 'compute.instance.finish_resize.start') - msg = test_notifier.NOTIFICATIONS[1] - self.assertEquals(msg['event_type'], + msg = fake_notifier.NOTIFICATIONS[1] + self.assertEquals(msg.event_type, 'compute.instance.finish_resize.end') - self.assertEquals(msg['priority'], 'INFO') - payload = msg['payload'] + self.assertEquals(msg.priority, 'INFO') + payload = msg.payload self.assertEquals(payload['tenant_id'], self.project_id) self.assertEquals(payload['user_id'], self.user_id) self.assertEquals(payload['instance_id'], instance.uuid) @@ -3627,7 +3625,7 @@ class ComputeTestCase(BaseTestCase): self.compute.run_instance(self.context, instance=instance) timeutils.set_time_override(cur_time) - test_notifier.NOTIFICATIONS = [] + fake_notifier.NOTIFICATIONS = [] instance.host = 'foo' instance.task_state = task_states.RESIZE_PREP @@ -3640,18 +3638,18 @@ class ComputeTestCase(BaseTestCase): instance.uuid, 'pre-migrating') - self.assertEquals(len(test_notifier.NOTIFICATIONS), 3) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals(msg['event_type'], + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 3) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEquals(msg.event_type, 'compute.instance.exists') - msg = test_notifier.NOTIFICATIONS[1] - self.assertEquals(msg['event_type'], + msg = fake_notifier.NOTIFICATIONS[1] + self.assertEquals(msg.event_type, 'compute.instance.resize.prep.start') - msg = test_notifier.NOTIFICATIONS[2] - self.assertEquals(msg['event_type'], + msg = fake_notifier.NOTIFICATIONS[2] + self.assertEquals(msg.event_type, 'compute.instance.resize.prep.end') - self.assertEquals(msg['priority'], 'INFO') - payload = msg['payload'] + self.assertEquals(msg.priority, 'INFO') + payload = msg.payload self.assertEquals(payload['tenant_id'], self.project_id) self.assertEquals(payload['user_id'], self.user_id) self.assertEquals(payload['instance_id'], instance.uuid) @@ -4186,7 +4184,7 @@ class ComputeTestCase(BaseTestCase): self.compute.network_api.setup_networks_on_host(c, instance, self.compute.host) - test_notifier.NOTIFICATIONS = [] + fake_notifier.NOTIFICATIONS = [] # start test self.mox.ReplayAll() migrate_data = {'is_shared_storage': False} @@ -4194,12 +4192,12 @@ class ComputeTestCase(BaseTestCase): block_migration=False, migrate_data=migrate_data) self.assertEqual(ret, None) - self.assertEqual(len(test_notifier.NOTIFICATIONS), 2) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEqual(msg['event_type'], + self.assertEqual(len(fake_notifier.NOTIFICATIONS), 2) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEqual(msg.event_type, 'compute.instance.live_migration.pre.start') - msg = test_notifier.NOTIFICATIONS[1] - self.assertEqual(msg['event_type'], + msg = fake_notifier.NOTIFICATIONS[1] + self.assertEqual(msg.event_type, 'compute.instance.live_migration.pre.end') # cleanup @@ -4218,7 +4216,6 @@ class ComputeTestCase(BaseTestCase): fake_bdms = [dict(volume_id='vol1-id'), dict(volume_id='vol2-id')] # creating mocks - self.mox.StubOutWithMock(rpc, 'call') self.mox.StubOutWithMock(self.compute.driver, 'get_instance_disk_info') self.mox.StubOutWithMock(self.compute.compute_rpcapi, @@ -4430,18 +4427,18 @@ class ComputeTestCase(BaseTestCase): self.compute.network_api.setup_networks_on_host(self.admin_ctxt, mox.IgnoreArg(), self.compute.host) - test_notifier.NOTIFICATIONS = [] + fake_notifier.NOTIFICATIONS = [] self.mox.ReplayAll() self.compute.post_live_migration_at_destination(self.admin_ctxt, self.instance) - self.assertEqual(len(test_notifier.NOTIFICATIONS), 2) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEqual(msg['event_type'], + self.assertEqual(len(fake_notifier.NOTIFICATIONS), 2) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEqual(msg.event_type, 'compute.instance.live_migration.post.dest.start') - msg = test_notifier.NOTIFICATIONS[1] - self.assertEqual(msg['event_type'], + msg = fake_notifier.NOTIFICATIONS[1] + self.assertEqual(msg.event_type, 'compute.instance.live_migration.post.dest.end') return self.compute.conductor_api.instance_get_by_uuid(self.admin_ctxt, @@ -4477,7 +4474,7 @@ class ComputeTestCase(BaseTestCase): inst_id = instance_ref['id'] instance = jsonutils.to_primitive(db.instance_get(c, inst_id)) - test_notifier.NOTIFICATIONS = [] + fake_notifier.NOTIFICATIONS = [] self.mox.StubOutWithMock(self.compute.network_api, 'setup_networks_on_host') @@ -4490,12 +4487,12 @@ class ComputeTestCase(BaseTestCase): ret = self.compute.rollback_live_migration_at_destination(c, instance=instance) self.assertEqual(ret, None) - self.assertEqual(len(test_notifier.NOTIFICATIONS), 2) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEqual(msg['event_type'], + self.assertEqual(len(fake_notifier.NOTIFICATIONS), 2) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEqual(msg.event_type, 'compute.instance.live_migration.rollback.dest.start') - msg = test_notifier.NOTIFICATIONS[1] - self.assertEqual(msg['event_type'], + msg = fake_notifier.NOTIFICATIONS[1] + self.assertEqual(msg.event_type, 'compute.instance.live_migration.rollback.dest.end') # cleanup @@ -6547,9 +6544,9 @@ class ComputeAPITestCase(BaseTestCase): self.assertEqual(metadata, {'key1': 'value1', 'key2': 'value2'}) self.assertEqual(meta_changes, [{'key2': ['+', 'value2']}]) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 1) - msg = test_notifier.NOTIFICATIONS[0] - payload = msg['payload'] + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 1) + msg = fake_notifier.NOTIFICATIONS[0] + payload = msg.payload self.assertTrue('metadata' in payload) self.assertEquals(payload['metadata'], metadata) @@ -6564,9 +6561,9 @@ class ComputeAPITestCase(BaseTestCase): 'key3': ['+', 'value3'], }]) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 2) - msg = test_notifier.NOTIFICATIONS[1] - payload = msg['payload'] + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 2) + msg = fake_notifier.NOTIFICATIONS[1] + payload = msg.payload self.assertTrue('metadata' in payload) self.assertEquals(payload['metadata'], metadata) @@ -6575,9 +6572,9 @@ class ComputeAPITestCase(BaseTestCase): self.assertEqual(metadata, {'key3': 'value3'}) self.assertEqual(meta_changes, [{'key2': ['-']}]) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 3) - msg = test_notifier.NOTIFICATIONS[2] - payload = msg['payload'] + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 3) + msg = fake_notifier.NOTIFICATIONS[2] + payload = msg.payload self.assertTrue('metadata' in payload) self.assertEquals(payload['metadata'], {}) @@ -7859,16 +7856,16 @@ class ComputeAPIAggrTestCase(BaseTestCase): # Ensure metadata can be updated. aggr = self.api.create_aggregate(self.context, 'fake_aggregate', 'fake_zone') - test_notifier.NOTIFICATIONS = [] + fake_notifier.NOTIFICATIONS = [] aggr = self.api.update_aggregate(self.context, aggr['id'], {'name': 'new_fake_aggregate'}) self.assertEqual(availability_zones._get_cache().get('cache'), None) - self.assertEqual(len(test_notifier.NOTIFICATIONS), 2) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEqual(msg['event_type'], + self.assertEqual(len(fake_notifier.NOTIFICATIONS), 2) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEqual(msg.event_type, 'aggregate.updateprop.start') - msg = test_notifier.NOTIFICATIONS[1] - self.assertEqual(msg['event_type'], + msg = fake_notifier.NOTIFICATIONS[1] + self.assertEqual(msg.event_type, 'aggregate.updateprop.end') def test_update_aggregate_metadata(self): @@ -7877,15 +7874,15 @@ class ComputeAPIAggrTestCase(BaseTestCase): 'fake_zone') metadata = {'foo_key1': 'foo_value1', 'foo_key2': 'foo_value2', } - test_notifier.NOTIFICATIONS = [] + fake_notifier.NOTIFICATIONS = [] aggr = self.api.update_aggregate_metadata(self.context, aggr['id'], metadata) - self.assertEqual(len(test_notifier.NOTIFICATIONS), 2) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEqual(msg['event_type'], + self.assertEqual(len(fake_notifier.NOTIFICATIONS), 2) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEqual(msg.event_type, 'aggregate.updatemetadata.start') - msg = test_notifier.NOTIFICATIONS[1] - self.assertEqual(msg['event_type'], + msg = fake_notifier.NOTIFICATIONS[1] + self.assertEqual(msg.event_type, 'aggregate.updatemetadata.end') metadata['foo_key1'] = None expected = self.api.update_aggregate_metadata(self.context, @@ -7896,24 +7893,24 @@ class ComputeAPIAggrTestCase(BaseTestCase): def test_delete_aggregate(self): # Ensure we can delete an aggregate. - test_notifier.NOTIFICATIONS = [] + fake_notifier.NOTIFICATIONS = [] aggr = self.api.create_aggregate(self.context, 'fake_aggregate', 'fake_zone') - self.assertEqual(len(test_notifier.NOTIFICATIONS), 2) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEqual(msg['event_type'], + self.assertEqual(len(fake_notifier.NOTIFICATIONS), 2) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEqual(msg.event_type, 'aggregate.create.start') - msg = test_notifier.NOTIFICATIONS[1] - self.assertEqual(msg['event_type'], + msg = fake_notifier.NOTIFICATIONS[1] + self.assertEqual(msg.event_type, 'aggregate.create.end') - test_notifier.NOTIFICATIONS = [] + fake_notifier.NOTIFICATIONS = [] self.api.delete_aggregate(self.context, aggr['id']) - self.assertEqual(len(test_notifier.NOTIFICATIONS), 2) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEqual(msg['event_type'], + self.assertEqual(len(fake_notifier.NOTIFICATIONS), 2) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEqual(msg.event_type, 'aggregate.delete.start') - msg = test_notifier.NOTIFICATIONS[1] - self.assertEqual(msg['event_type'], + msg = fake_notifier.NOTIFICATIONS[1] + self.assertEqual(msg.event_type, 'aggregate.delete.end') db.aggregate_get(self.context.elevated(read_deleted='yes'), aggr['id']) @@ -7945,15 +7942,15 @@ class ComputeAPIAggrTestCase(BaseTestCase): self.stubs.Set(self.api.compute_rpcapi, 'add_aggregate_host', fake_add_aggregate_host) - test_notifier.NOTIFICATIONS = [] + fake_notifier.NOTIFICATIONS = [] aggr = self.api.add_host_to_aggregate(self.context, aggr['id'], fake_host) - self.assertEqual(len(test_notifier.NOTIFICATIONS), 2) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEqual(msg['event_type'], + self.assertEqual(len(fake_notifier.NOTIFICATIONS), 2) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEqual(msg.event_type, 'aggregate.addhost.start') - msg = test_notifier.NOTIFICATIONS[1] - self.assertEqual(msg['event_type'], + msg = fake_notifier.NOTIFICATIONS[1] + self.assertEqual(msg.event_type, 'aggregate.addhost.end') self.assertEqual(len(aggr['hosts']), 1) @@ -8047,16 +8044,16 @@ class ComputeAPIAggrTestCase(BaseTestCase): self.stubs.Set(self.api.compute_rpcapi, 'remove_aggregate_host', fake_remove_aggregate_host) - test_notifier.NOTIFICATIONS = [] + fake_notifier.NOTIFICATIONS = [] expected = self.api.remove_host_from_aggregate(self.context, aggr['id'], host_to_remove) - self.assertEqual(len(test_notifier.NOTIFICATIONS), 2) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEqual(msg['event_type'], + self.assertEqual(len(fake_notifier.NOTIFICATIONS), 2) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEqual(msg.event_type, 'aggregate.removehost.start') - msg = test_notifier.NOTIFICATIONS[1] - self.assertEqual(msg['event_type'], + msg = fake_notifier.NOTIFICATIONS[1] + self.assertEqual(msg.event_type, 'aggregate.removehost.end') self.assertEqual(len(aggr['hosts']) - 1, len(expected['hosts'])) diff --git a/nova/tests/compute/test_compute_api.py b/nova/tests/compute/test_compute_api.py index 980af30cc7dd..cd6c95faaa98 100644 --- a/nova/tests/compute/test_compute_api.py +++ b/nova/tests/compute/test_compute_api.py @@ -422,7 +422,8 @@ class _ComputeAPIUnitTestMixIn(object): if inst.host == 'down-host': inst.info_cache.delete() - compute_utils.notify_about_instance_usage(self.context, + compute_utils.notify_about_instance_usage(mox.IgnoreArg(), + self.context, inst, '%s.start' % delete_type) if not self.is_cells: @@ -445,6 +446,7 @@ class _ComputeAPIUnitTestMixIn(object): reservations=None) db.instance_destroy(self.context, inst.uuid, constraint=None) compute_utils.notify_about_instance_usage( + mox.IgnoreArg(), self.context, inst, '%s.end' % delete_type, system_metadata='sys-meta') diff --git a/nova/tests/compute/test_compute_utils.py b/nova/tests/compute/test_compute_utils.py index e04726e918e3..accc9dd7f895 100644 --- a/nova/tests/compute/test_compute_utils.py +++ b/nova/tests/compute/test_compute_utils.py @@ -2,6 +2,7 @@ # Copyright 2011 OpenStack Foundation # All Rights Reserved. +# Copyright 2013 Red Hat, Inc. # # 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 @@ -28,13 +29,13 @@ from nova import db from nova import exception from nova.image import glance from nova.network import api as network_api +from nova import notifier as notify from nova.openstack.common import importutils from nova.openstack.common import jsonutils -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_instance_actions from nova.tests import fake_network +from nova.tests import fake_notifier import nova.tests.image.fake CONF = cfg.CONF @@ -236,17 +237,16 @@ class UsageInfoTestCase(test.TestCase): self.stubs.Set(network_api.API, 'get_instance_nw_info', fake_get_nw_info) - notifier_api._reset_drivers() - self.addCleanup(notifier_api._reset_drivers) + fake_notifier.stub_notifier(self.stubs) + self.addCleanup(fake_notifier.reset) + self.flags(use_local=True, group='conductor') self.flags(compute_driver='nova.virt.fake.FakeDriver', - notification_driver=[test_notifier.__name__], network_manager='nova.network.manager.FlatManager') self.compute = importutils.import_object(CONF.compute_manager) self.user_id = 'fake' self.project_id = 'fake' self.context = context.RequestContext(self.user_id, self.project_id) - test_notifier.NOTIFICATIONS = [] def fake_show(meh, context, id): return {'id': 1, 'properties': {'kernel_id': 1, 'ramdisk_id': 1}} @@ -284,12 +284,13 @@ class UsageInfoTestCase(test.TestCase): db.instance_system_metadata_update(self.context, instance['uuid'], sys_metadata, False) instance = db.instance_get(self.context, instance_id) - compute_utils.notify_usage_exists(self.context, instance) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 1) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals(msg['priority'], 'INFO') - self.assertEquals(msg['event_type'], 'compute.instance.exists') - payload = msg['payload'] + compute_utils.notify_usage_exists( + notify.get_notifier('compute'), self.context, instance) + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 1) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEquals(msg.priority, 'INFO') + self.assertEquals(msg.event_type, 'compute.instance.exists') + payload = msg.payload self.assertEquals(payload['tenant_id'], self.project_id) self.assertEquals(payload['user_id'], self.user_id) self.assertEquals(payload['instance_id'], instance['uuid']) @@ -323,11 +324,12 @@ class UsageInfoTestCase(test.TestCase): jsonutils.to_primitive(instance)) instance = db.instance_get(self.context.elevated(read_deleted='yes'), instance_id) - compute_utils.notify_usage_exists(self.context, instance) - msg = test_notifier.NOTIFICATIONS[-1] - self.assertEquals(msg['priority'], 'INFO') - self.assertEquals(msg['event_type'], 'compute.instance.exists') - payload = msg['payload'] + compute_utils.notify_usage_exists( + notify.get_notifier('compute'), self.context, instance) + msg = fake_notifier.NOTIFICATIONS[-1] + self.assertEquals(msg.priority, 'INFO') + self.assertEquals(msg.event_type, 'compute.instance.exists') + payload = msg.payload self.assertEquals(payload['tenant_id'], self.project_id) self.assertEquals(payload['user_id'], self.user_id) self.assertEquals(payload['instance_id'], instance['uuid']) @@ -351,11 +353,12 @@ class UsageInfoTestCase(test.TestCase): instance = db.instance_get(self.context, instance_id) self.compute.terminate_instance(self.context, jsonutils.to_primitive(instance)) - compute_utils.notify_usage_exists(self.context, instance) - msg = test_notifier.NOTIFICATIONS[-1] - self.assertEquals(msg['priority'], 'INFO') - self.assertEquals(msg['event_type'], 'compute.instance.exists') - payload = msg['payload'] + compute_utils.notify_usage_exists( + notify.get_notifier('compute'), self.context, instance) + msg = fake_notifier.NOTIFICATIONS[-1] + self.assertEquals(msg.priority, 'INFO') + self.assertEquals(msg.event_type, 'compute.instance.exists') + payload = msg.payload self.assertEquals(payload['tenant_id'], self.project_id) self.assertEquals(payload['user_id'], self.user_id) self.assertEquals(payload['instance_id'], instance['uuid']) @@ -385,13 +388,15 @@ class UsageInfoTestCase(test.TestCase): # NOTE(russellb) Make sure our instance has the latest system_metadata # in it. instance = db.instance_get(self.context, instance_id) - compute_utils.notify_about_instance_usage(self.context, instance, - 'create.start', extra_usage_info=extra_usage_info) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 1) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals(msg['priority'], 'INFO') - self.assertEquals(msg['event_type'], 'compute.instance.create.start') - payload = msg['payload'] + compute_utils.notify_about_instance_usage( + notify.get_notifier('compute'), + self.context, instance, 'create.start', + extra_usage_info=extra_usage_info) + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 1) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEquals(msg.priority, 'INFO') + self.assertEquals(msg.event_type, 'compute.instance.create.start') + payload = msg.payload self.assertEquals(payload['tenant_id'], self.project_id) self.assertEquals(payload['user_id'], self.user_id) self.assertEquals(payload['instance_id'], instance['uuid']) @@ -416,11 +421,11 @@ class UsageInfoTestCase(test.TestCase): compute_utils.notify_about_aggregate_update(self.context, "create.end", aggregate_payload) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 1) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals(msg['priority'], 'INFO') - self.assertEquals(msg['event_type'], 'aggregate.create.end') - payload = msg['payload'] + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 1) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEquals(msg.priority, 'INFO') + self.assertEquals(msg.event_type, 'aggregate.create.end') + payload = msg.payload self.assertEquals(payload['aggregate_id'], 1) def test_notify_about_aggregate_update_with_name(self): @@ -429,11 +434,11 @@ class UsageInfoTestCase(test.TestCase): compute_utils.notify_about_aggregate_update(self.context, "create.start", aggregate_payload) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 1) - msg = test_notifier.NOTIFICATIONS[0] - self.assertEquals(msg['priority'], 'INFO') - self.assertEquals(msg['event_type'], 'aggregate.create.start') - payload = msg['payload'] + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 1) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEquals(msg.priority, 'INFO') + self.assertEquals(msg.event_type, 'aggregate.create.start') + payload = msg.payload self.assertEquals(payload['name'], 'fakegroup') def test_notify_about_aggregate_update_without_name_id(self): @@ -442,4 +447,4 @@ class UsageInfoTestCase(test.TestCase): compute_utils.notify_about_aggregate_update(self.context, "create.start", aggregate_payload) - self.assertEquals(len(test_notifier.NOTIFICATIONS), 0) + self.assertEquals(len(fake_notifier.NOTIFICATIONS), 0) diff --git a/nova/tests/conductor/test_conductor.py b/nova/tests/conductor/test_conductor.py index fc1ca4a76719..c6ff89160082 100644 --- a/nova/tests/conductor/test_conductor.py +++ b/nova/tests/conductor/test_conductor.py @@ -1,4 +1,5 @@ # Copyright 2012 IBM Corp. +# Copyright 2013 Red Hat, Inc. # # 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 @@ -34,8 +35,6 @@ from nova import notifications from nova.objects import instance as instance_obj from nova.objects import migration as migration_obj from nova.openstack.common import jsonutils -from nova.openstack.common.notifier import api as notifier_api -from nova.openstack.common.notifier import test_notifier from nova.openstack.common.rpc import common as rpc_common from nova.openstack.common import timeutils from nova import quota @@ -44,6 +43,7 @@ from nova import test from nova.tests.compute import test_compute from nova.tests import fake_instance from nova.tests import fake_instance_actions +from nova.tests import fake_notifier from nova.tests.objects import test_migration from nova import utils @@ -67,10 +67,8 @@ class _BaseTestCase(object): self.project_id = 'fake' self.context = FakeContext(self.user_id, self.project_id) - notifier_api._reset_drivers() - self.addCleanup(notifier_api._reset_drivers) - self.flags(notification_driver=[test_notifier.__name__]) - test_notifier.NOTIFICATIONS = [] + fake_notifier.stub_notifier(self.stubs) + self.addCleanup(fake_notifier.reset) def _create_fake_instance(self, params=None, type_name='m1.tiny'): if not params: @@ -352,7 +350,6 @@ class _BaseTestCase(object): def test_vol_usage_update(self): self.mox.StubOutWithMock(db, 'vol_usage_update') - self.mox.StubOutWithMock(test_notifier, 'notify') self.mox.StubOutWithMock(compute_utils, 'usage_volume_info') fake_inst = {'uuid': 'fake-uuid', @@ -368,10 +365,6 @@ class _BaseTestCase(object): fake_inst['availability_zone'], False).AndReturn('fake-usage') compute_utils.usage_volume_info('fake-usage').AndReturn('fake-info') - notifier_api.notify(self.context, - 'conductor.%s' % self.conductor_manager.host, - 'volume.usage', notifier_api.INFO, - 'fake-info') self.mox.ReplayAll() @@ -379,6 +372,14 @@ class _BaseTestCase(object): 22, 33, 44, 55, fake_inst, 'fake-update-time', False) + self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) + msg = fake_notifier.NOTIFICATIONS[0] + self.assertEqual('conductor.%s' % self.conductor_manager.host, + msg.publisher_id) + self.assertEqual('volume.usage', msg.event_type) + self.assertEqual('INFO', msg.priority) + self.assertEqual('fake-info', msg.payload) + def test_compute_node_create(self): self.mox.StubOutWithMock(db, 'compute_node_create') db.compute_node_create(self.context, 'fake-values').AndReturn( @@ -471,7 +472,9 @@ class _BaseTestCase(object): notifications.audit_period_bounds(False).AndReturn(('start', 'end')) notifications.bandwidth_usage(instance, 'start', True).AndReturn( 'bw_usage') - compute_utils.notify_about_instance_usage(self.context, instance, + notifier = self.conductor_manager.notifier + compute_utils.notify_about_instance_usage(notifier, + self.context, instance, 'exists', system_metadata={}, extra_usage_info=info) diff --git a/nova/tests/fake_notifier.py b/nova/tests/fake_notifier.py new file mode 100644 index 000000000000..135240827939 --- /dev/null +++ b/nova/tests/fake_notifier.py @@ -0,0 +1,53 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Red Hat, Inc. +# +# 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 collections +import functools + +from nova import notifier + +NOTIFICATIONS = [] + + +def reset(): + del NOTIFICATIONS[:] + + +FakeMessage = collections.namedtuple('Message', + ['publisher_id', 'priority', + 'event_type', 'payload']) + + +class FakeNotifier(object): + + def __init__(self, publisher_id): + self.publisher_id = publisher_id + for priority in ['debug', 'info', 'warn', 'error', 'critical']: + setattr(self, priority, + functools.partial(self._notify, priority.upper())) + + def prepare(self, publisher_id=None): + if publisher_id is None: + publisher_id = self.publisher_id + return self.__class__(publisher_id) + + def _notify(self, priority, ctxt, event_type, payload): + msg = FakeMessage(self.publisher_id, priority, event_type, payload) + NOTIFICATIONS.append(msg) + + +def stub_notifier(stubs): + stubs.Set(notifier, 'Notifier', FakeNotifier) diff --git a/nova/tests/scheduler/test_scheduler.py b/nova/tests/scheduler/test_scheduler.py index 39f18cd744c8..4502d4ce8675 100644 --- a/nova/tests/scheduler/test_scheduler.py +++ b/nova/tests/scheduler/test_scheduler.py @@ -20,6 +20,7 @@ Tests For Scheduler """ import mox +from oslo.config import cfg from nova.compute import api as compute_api from nova.compute import task_states @@ -31,8 +32,8 @@ from nova import context from nova import db from nova import exception from nova.image import glance +from nova import notifier as notify from nova.objects import instance as instance_obj -from nova.openstack.common.notifier import api as notifier from nova.openstack.common.rpc import common as rpc_common from nova.scheduler import driver from nova.scheduler import manager @@ -45,6 +46,8 @@ from nova.tests import matchers from nova.tests.scheduler import fakes from nova import utils +CONF = cfg.CONF + class SchedulerManagerTestCase(test.NoDBTestCase): """Test case for scheduler manager.""" @@ -433,13 +436,15 @@ class SchedulerManagerTestCase(test.NoDBTestCase): self.mox.StubOutWithMock(db, 'instance_update_and_get_original') self.mox.StubOutWithMock(db, 'instance_fault_create') - self.mox.StubOutWithMock(notifier, 'notify') + self.mox.StubOutWithMock(notify, 'get_notifier') + notifier = self.mox.CreateMockAnything() + notify.get_notifier('conductor', CONF.host).AndReturn(notifier) + notify.get_notifier('scheduler').AndReturn(notifier) db.instance_update_and_get_original(self.context, 'fake-uuid', updates).AndReturn((None, fake_inst)) db.instance_fault_create(self.context, mox.IgnoreArg()) - notifier.notify(self.context, mox.IgnoreArg(), 'scheduler.foo', - notifier.ERROR, mox.IgnoreArg()) + notifier.error(self.context, 'scheduler.foo', mox.IgnoreArg()) self.mox.ReplayAll() self.manager._set_vm_state_and_notify('foo', {'vm_state': 'foo'}, @@ -557,14 +562,15 @@ class SchedulerTestCase(test.NoDBTestCase): instance = {'uuid': 'fake-uuid'} self.mox.StubOutWithMock(db, 'instance_update_and_get_original') self.mox.StubOutWithMock(db, 'instance_fault_create') - self.mox.StubOutWithMock(notifier, 'notify') db.instance_update_and_get_original(self.context, instance['uuid'], mox.IgnoreArg()).AndReturn( (None, instance)) db.instance_fault_create(self.context, mox.IgnoreArg()) - notifier.notify(self.context, mox.IgnoreArg(), - 'scheduler.run_instance', - notifier.ERROR, mox.IgnoreArg()) + self.mox.StubOutWithMock(notify, 'get_notifier') + notifier = self.mox.CreateMockAnything() + notify.get_notifier('conductor', CONF.host).AndReturn(notifier) + notify.get_notifier('scheduler').AndReturn(notifier) + notifier.error(self.context, 'scheduler.run_instance', mox.IgnoreArg()) self.mox.ReplayAll() driver.handle_schedule_error(self.context, diff --git a/nova/tests/scheduler/test_scheduler_utils.py b/nova/tests/scheduler/test_scheduler_utils.py index 84db590f5270..31c5b54c5a74 100644 --- a/nova/tests/scheduler/test_scheduler_utils.py +++ b/nova/tests/scheduler/test_scheduler_utils.py @@ -16,15 +16,18 @@ Tests For Scheduler Utils """ import mox +from oslo.config import cfg from nova.compute import utils as compute_utils from nova.conductor import api as conductor_api from nova import db from nova import notifications -from nova.openstack.common.notifier import api as notifier +from nova import notifier as notify from nova.scheduler import utils as scheduler_utils from nova import test +CONF = cfg.CONF + class SchedulerUtilsTestCase(test.NoDBTestCase): """Test case for scheduler utils methods.""" @@ -38,13 +41,16 @@ class SchedulerUtilsTestCase(test.NoDBTestCase): service = 'fake-service' method = 'fake-method' exc_info = 'exc_info' - publisher_id = 'fake-publisher-id' self.mox.StubOutWithMock(compute_utils, 'add_instance_fault_from_exc') self.mox.StubOutWithMock(notifications, 'send_update') self.mox.StubOutWithMock(db, 'instance_update_and_get_original') - self.mox.StubOutWithMock(notifier, 'publisher_id') + + self.mox.StubOutWithMock(notify, 'get_notifier') + notifier = self.mox.CreateMockAnything() + notify.get_notifier('conductor', CONF.host).AndReturn(notifier) + notify.get_notifier(service).AndReturn(notifier) old_ref = 'old_ref' new_ref = 'new_ref' @@ -61,15 +67,13 @@ class SchedulerUtilsTestCase(test.NoDBTestCase): payload = dict(request_spec=request_spec, instance_properties=request_spec.get( - 'instance_properties'), + 'instance_properties', {}), instance_id=uuid, state='fake-vm-state', method=method, reason=exc_info) event_type = '%s.%s' % (service, method) - notifier.publisher_id(service).AndReturn(publisher_id) - notifier.notify(self.context, publisher_id, - event_type, notifier.ERROR, payload) + notifier.error(self.context, event_type, payload) self.mox.ReplayAll() diff --git a/nova/tests/test_exception.py b/nova/tests/test_exception.py index 9b53fab98087..0b171641e2d2 100644 --- a/nova/tests/test_exception.py +++ b/nova/tests/test_exception.py @@ -22,21 +22,17 @@ from nova import test class FakeNotifier(object): - """Acts like the nova.notifier.api module.""" - ERROR = 88 + """Acts like messaging.Notifier.""" def __init__(self): - self.provided_publisher = None + self.provided_context = None self.provided_event = None - self.provided_priority = None self.provided_payload = None - def notify(self, context, publisher, event, priority, payload): - self.provided_publisher = publisher - self.provided_event = event - self.provided_priority = priority - self.provided_payload = payload + def error(self, context, event, payload): self.provided_context = context + self.provided_event = event + self.provided_payload = payload def good_function(self, context): @@ -49,18 +45,16 @@ def bad_function_exception(self, context, extra, blah="a", boo="b", zoo=None): class WrapExceptionTestCase(test.TestCase): def test_wrap_exception_good_return(self): - wrapped = exception.wrap_exception('foo', 'bar') + wrapped = exception.wrap_exception('foo') self.assertEquals(99, wrapped(good_function)(1, 2)) def test_wrap_exception_with_notifier(self): notifier = FakeNotifier() - wrapped = exception.wrap_exception(notifier, "publisher") + wrapped = exception.wrap_exception(notifier) ctxt = context.get_admin_context() self.assertRaises(test.TestingException, wrapped(bad_function_exception), 1, ctxt, 3, zoo=3) - self.assertEquals(notifier.provided_publisher, "publisher") self.assertEquals(notifier.provided_event, "bad_function_exception") - self.assertEquals(notifier.provided_priority, notifier.ERROR) self.assertEquals(notifier.provided_context, ctxt) for key in ['exception', 'args']: self.assertTrue(key in notifier.provided_payload.keys()) diff --git a/nova/tests/test_notifications.py b/nova/tests/test_notifications.py index 2ab94e586dbe..f80b45b100d3 100644 --- a/nova/tests/test_notifications.py +++ b/nova/tests/test_notifications.py @@ -28,10 +28,9 @@ from nova import context from nova import db from nova.network import api as network_api from nova import notifications -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 +from nova.tests import fake_notifier CONF = cfg.CONF CONF.import_opt('compute_driver', 'nova.virt.driver') @@ -53,10 +52,10 @@ class NotificationsTestCase(test.TestCase): fake_get_nw_info) fake_network.set_stub_network_methods(self.stubs) - notifier_api._reset_drivers() - self.addCleanup(notifier_api._reset_drivers) + fake_notifier.stub_notifier(self.stubs) + self.addCleanup(fake_notifier.reset) + self.flags(compute_driver='nova.virt.fake.FakeDriver', - notification_driver=[test_notifier.__name__], network_manager='nova.network.manager.FlatManager', notify_on_state_change="vm_and_task_state", host='testhost') @@ -64,7 +63,6 @@ class NotificationsTestCase(test.TestCase): self.user_id = 'fake' self.project_id = 'fake' self.context = context.RequestContext(self.user_id, self.project_id) - test_notifier.NOTIFICATIONS = [] self.instance = self._wrapped_create() @@ -91,7 +89,7 @@ class NotificationsTestCase(test.TestCase): def test_send_api_fault_disabled(self): self.flags(notify_api_faults=False) notifications.send_api_fault("http://example.com/foo", 500, None) - self.assertEquals(0, len(test_notifier.NOTIFICATIONS)) + self.assertEquals(0, len(fake_notifier.NOTIFICATIONS)) def test_send_api_fault(self): self.flags(notify_api_faults=True) @@ -104,13 +102,13 @@ class NotificationsTestCase(test.TestCase): notifications.send_api_fault("http://example.com/foo", 500, exception) - self.assertEquals(1, len(test_notifier.NOTIFICATIONS)) - n = test_notifier.NOTIFICATIONS[0] - self.assertEquals(n['priority'], 'ERROR') - self.assertEquals(n['event_type'], 'api.fault') - self.assertEquals(n['payload']['url'], 'http://example.com/foo') - self.assertEquals(n['payload']['status'], 500) - self.assertTrue(n['payload']['exception'] is not None) + self.assertEquals(1, len(fake_notifier.NOTIFICATIONS)) + n = fake_notifier.NOTIFICATIONS[0] + self.assertEquals(n.priority, 'ERROR') + self.assertEquals(n.event_type, 'api.fault') + self.assertEquals(n.payload['url'], 'http://example.com/foo') + self.assertEquals(n.payload['status'], 500) + self.assertTrue(n.payload['exception'] is not None) def test_notif_disabled(self): @@ -130,7 +128,7 @@ class NotificationsTestCase(test.TestCase): verify_states=True) notifications.send_update(self.context, old, self.instance) - self.assertEquals(0, len(test_notifier.NOTIFICATIONS)) + self.assertEquals(0, len(fake_notifier.NOTIFICATIONS)) def test_task_notif(self): @@ -150,13 +148,13 @@ class NotificationsTestCase(test.TestCase): old_vm_state, new_vm_state, old_task_state, new_task_state, verify_states=True) - self.assertEquals(0, len(test_notifier.NOTIFICATIONS)) + self.assertEquals(0, len(fake_notifier.NOTIFICATIONS)) # ok now enable task state notifcations and re-try self.flags(notify_on_state_change="vm_and_task_state") notifications.send_update(self.context, old, self.instance) - self.assertEquals(1, len(test_notifier.NOTIFICATIONS)) + self.assertEquals(1, len(fake_notifier.NOTIFICATIONS)) def test_send_no_notif(self): @@ -170,7 +168,7 @@ class NotificationsTestCase(test.TestCase): old_vm_state, new_vm_state, old_task_state, new_task_state, service="compute", host=None, verify_states=True) - self.assertEquals(0, len(test_notifier.NOTIFICATIONS)) + self.assertEquals(0, len(fake_notifier.NOTIFICATIONS)) def test_send_on_vm_change(self): @@ -180,7 +178,7 @@ class NotificationsTestCase(test.TestCase): self.instance['uuid'], params) notifications.send_update(self.context, old_ref, new_ref) - self.assertEquals(1, len(test_notifier.NOTIFICATIONS)) + self.assertEquals(1, len(fake_notifier.NOTIFICATIONS)) def test_send_on_task_change(self): @@ -190,23 +188,23 @@ class NotificationsTestCase(test.TestCase): self.instance['uuid'], params) notifications.send_update(self.context, old_ref, new_ref) - self.assertEquals(1, len(test_notifier.NOTIFICATIONS)) + self.assertEquals(1, len(fake_notifier.NOTIFICATIONS)) def test_no_update_with_states(self): notifications.send_update_with_states(self.context, self.instance, vm_states.BUILDING, vm_states.BUILDING, task_states.SPAWNING, task_states.SPAWNING, verify_states=True) - self.assertEquals(0, len(test_notifier.NOTIFICATIONS)) + self.assertEquals(0, len(fake_notifier.NOTIFICATIONS)) def test_vm_update_with_states(self): notifications.send_update_with_states(self.context, self.instance, vm_states.BUILDING, vm_states.ACTIVE, task_states.SPAWNING, task_states.SPAWNING, verify_states=True) - self.assertEquals(1, len(test_notifier.NOTIFICATIONS)) - notif = test_notifier.NOTIFICATIONS[0] - payload = notif["payload"] + self.assertEquals(1, len(fake_notifier.NOTIFICATIONS)) + notif = fake_notifier.NOTIFICATIONS[0] + payload = notif.payload access_ip_v4 = self.instance["access_ip_v4"] access_ip_v6 = self.instance["access_ip_v6"] display_name = self.instance["display_name"] @@ -229,9 +227,9 @@ class NotificationsTestCase(test.TestCase): notifications.send_update_with_states(self.context, self.instance, vm_states.BUILDING, vm_states.BUILDING, task_states.SPAWNING, None, verify_states=True) - self.assertEquals(1, len(test_notifier.NOTIFICATIONS)) - notif = test_notifier.NOTIFICATIONS[0] - payload = notif["payload"] + self.assertEquals(1, len(fake_notifier.NOTIFICATIONS)) + notif = fake_notifier.NOTIFICATIONS[0] + payload = notif.payload access_ip_v4 = self.instance["access_ip_v4"] access_ip_v6 = self.instance["access_ip_v6"] display_name = self.instance["display_name"] @@ -250,31 +248,31 @@ class NotificationsTestCase(test.TestCase): notifications.send_update_with_states(self.context, self.instance, vm_states.BUILDING, vm_states.BUILDING, task_states.SPAWNING, None) - self.assertEquals(1, len(test_notifier.NOTIFICATIONS)) + self.assertEquals(1, len(fake_notifier.NOTIFICATIONS)) # service name should default to 'compute' - notif = test_notifier.NOTIFICATIONS[0] - self.assertEquals('compute.testhost', notif['publisher_id']) + notif = fake_notifier.NOTIFICATIONS[0] + self.assertEquals('compute.testhost', notif.publisher_id) def test_update_with_service_name(self): notifications.send_update_with_states(self.context, self.instance, vm_states.BUILDING, vm_states.BUILDING, task_states.SPAWNING, None, service="testservice") - self.assertEquals(1, len(test_notifier.NOTIFICATIONS)) + self.assertEquals(1, len(fake_notifier.NOTIFICATIONS)) # service name should default to 'compute' - notif = test_notifier.NOTIFICATIONS[0] - self.assertEquals('testservice.testhost', notif['publisher_id']) + notif = fake_notifier.NOTIFICATIONS[0] + self.assertEquals('testservice.testhost', notif.publisher_id) def test_update_with_host_name(self): notifications.send_update_with_states(self.context, self.instance, vm_states.BUILDING, vm_states.BUILDING, task_states.SPAWNING, None, host="someotherhost") - self.assertEquals(1, len(test_notifier.NOTIFICATIONS)) + self.assertEquals(1, len(fake_notifier.NOTIFICATIONS)) # service name should default to 'compute' - notif = test_notifier.NOTIFICATIONS[0] - self.assertEquals('compute.someotherhost', notif['publisher_id']) + notif = fake_notifier.NOTIFICATIONS[0] + self.assertEquals('compute.someotherhost', notif.publisher_id) def test_payload_has_fixed_ip_labels(self): info = notifications.info_from_instance(self.context, self.instance, @@ -284,9 +282,9 @@ class NotificationsTestCase(test.TestCase): def test_send_access_ip_update(self): notifications.send_update(self.context, self.instance, self.instance) - self.assertEquals(1, len(test_notifier.NOTIFICATIONS)) - notif = test_notifier.NOTIFICATIONS[0] - payload = notif["payload"] + self.assertEquals(1, len(fake_notifier.NOTIFICATIONS)) + notif = fake_notifier.NOTIFICATIONS[0] + payload = notif.payload access_ip_v4 = self.instance["access_ip_v4"] access_ip_v6 = self.instance["access_ip_v6"] @@ -297,9 +295,9 @@ class NotificationsTestCase(test.TestCase): param = {"display_name": "new_display_name"} new_name_inst = self._wrapped_create(params=param) notifications.send_update(self.context, self.instance, new_name_inst) - self.assertEquals(1, len(test_notifier.NOTIFICATIONS)) - notif = test_notifier.NOTIFICATIONS[0] - payload = notif["payload"] + self.assertEquals(1, len(fake_notifier.NOTIFICATIONS)) + notif = fake_notifier.NOTIFICATIONS[0] + payload = notif.payload old_display_name = self.instance["display_name"] new_display_name = new_name_inst["display_name"] @@ -323,4 +321,4 @@ class NotificationsTestCase(test.TestCase): fail_sending) notifications.send_update(self.context, self.instance, self.instance) - self.assertEquals(0, len(test_notifier.NOTIFICATIONS)) + self.assertEquals(0, len(fake_notifier.NOTIFICATIONS)) diff --git a/nova/utils.py b/nova/utils.py index 4c29eb937d3a..09d1dc9dc6c2 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -52,7 +52,7 @@ from nova.openstack.common import processutils from nova.openstack.common.rpc import common as rpc_common from nova.openstack.common import timeutils -notify_decorator = 'nova.openstack.common.notifier.api.notify_decorator' +notify_decorator = 'nova.notifications.notify_decorator' monkey_patch_opts = [ cfg.BoolOpt('monkey_patch', @@ -719,10 +719,10 @@ def monkey_patch(): using CONF.monkey_patch_modules. The format is "Module path:Decorator function". Example: - 'nova.api.ec2.cloud:nova.openstack.common.notifier.api.notify_decorator' + 'nova.api.ec2.cloud:nova.notifications.notify_decorator' Parameters of the decorator is as follows. - (See nova.openstack.common.notifier.api.notify_decorator) + (See nova.notifications.notify_decorator) name - name of the function function - object of the function diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index 6af3974823f0..462b9844e8e3 100755 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -70,6 +70,7 @@ from nova.compute import vm_mode from nova import context as nova_context from nova import exception from nova.image import glance +from nova import notifier from nova.objects import instance as instance_obj from nova.openstack.common import excutils from nova.openstack.common import fileutils @@ -78,7 +79,6 @@ 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 loopingcall -from nova.openstack.common.notifier import api as notifier from nova.openstack.common import processutils from nova.openstack.common import xmlutils from nova.pci import pci_whitelist @@ -676,12 +676,9 @@ class LibvirtDriver(driver.ComputeDriver): payload = dict(ip=LibvirtDriver.get_host_ip_addr(), method='_connect', reason=ex) - notifier.notify(nova_context.get_admin_context(), - notifier.publisher_id('compute'), - 'compute.libvirt.error', - notifier.ERROR, - payload) - pass + notifier.get_notifier('compute').error( + nova_context.get_admin_context(), + 'compute.libvirt.error', payload) def get_num_instances(self): """Efficient override of base instance_exists method."""