Disable notifications

As part of the manila-telemetry integration work
we are now triggering notifications for several
events. We should provide a way to disable those.

In this patch-set we define a decorator that can be
used to change the behavior of those classes used
to emit notification.

Partially-Implements: bp ceilometer-integration

Change-Id: I806e0133e9fe3ad5cc35ad1e000e5ca61ff3b8ca
This commit is contained in:
Victoria Martinez de la Cruz 2017-07-06 19:50:08 -03:00
parent 93f4e862b0
commit e745fb7a8f
7 changed files with 132 additions and 4 deletions

View File

@ -32,6 +32,7 @@ from oslo_serialization import jsonutils
import manila.context import manila.context
import manila.exception import manila.exception
from manila import utils
CONF = cfg.CONF CONF = cfg.CONF
TRANSPORT = None TRANSPORT = None
@ -53,9 +54,13 @@ def init(conf):
conf, conf,
allowed_remote_exmods=exmods) allowed_remote_exmods=exmods)
serializer = RequestContextSerializer(JsonPayloadSerializer()) if utils.notifications_enabled(conf):
NOTIFIER = messaging.Notifier(NOTIFICATION_TRANSPORT, json_serializer = messaging.JsonPayloadSerializer()
serializer=serializer) serializer = RequestContextSerializer(json_serializer)
NOTIFIER = messaging.Notifier(NOTIFICATION_TRANSPORT,
serializer=serializer)
else:
NOTIFIER = utils.DO_NOTHING
def initialized(): def initialized():
@ -141,6 +146,7 @@ def get_server(target, endpoints, serializer=None):
access_policy=access_policy) access_policy=access_policy)
@utils.if_notifications_enabled
def get_notifier(service=None, host=None, publisher_id=None): def get_notifier(service=None, host=None, publisher_id=None):
assert NOTIFIER is not None assert NOTIFIER is not None
if not publisher_id: if not publisher_id:

View File

@ -20,6 +20,7 @@ from oslo_config import cfg
from manila.common import constants from manila.common import constants
from manila import rpc from manila import rpc
from manila import utils
DEFAULT_POOL_NAME = '_pool0' DEFAULT_POOL_NAME = '_pool0'
CONF = cfg.CONF CONF = cfg.CONF
@ -109,6 +110,7 @@ def cast_access_object_to_dict_in_readonly(rules):
return dict_rules return dict_rules
@utils.if_notifications_enabled
def notify_about_share_usage(context, share, share_instance, def notify_about_share_usage(context, share, share_instance,
event_suffix, extra_usage_info=None, host=None): event_suffix, extra_usage_info=None, host=None):

View File

@ -30,6 +30,7 @@ from oslo_concurrency import lockutils
from oslo_config import cfg from oslo_config import cfg
from oslo_config import fixture as config_fixture from oslo_config import fixture as config_fixture
import oslo_i18n import oslo_i18n
import oslo_messaging
from oslo_messaging import conffixture as messaging_conffixture from oslo_messaging import conffixture as messaging_conffixture
from oslo_utils import uuidutils from oslo_utils import uuidutils
import oslotest.base as base_test import oslotest.base as base_test
@ -140,6 +141,11 @@ class TestCase(base_test.BaseTestCase):
self.messaging_conf.transport_driver = 'fake' self.messaging_conf.transport_driver = 'fake'
self.messaging_conf.response_timeout = 15 self.messaging_conf.response_timeout = 15
self.useFixture(self.messaging_conf) self.useFixture(self.messaging_conf)
oslo_messaging.get_notification_transport(CONF)
self.override_config('driver', ['test'],
group='oslo_messaging_notifications')
rpc.init(CONF) rpc.init(CONF)
mock.patch('keystoneauth1.loading.load_auth_from_conf_options').start() mock.patch('keystoneauth1.loading.load_auth_from_conf_options').start()
@ -373,3 +379,8 @@ class TestCase(base_test.BaseTestCase):
self.assertEqual(call[0], posargs[0]) self.assertEqual(call[0], posargs[0])
self.assertEqual(call[1], posargs[2]) self.assertEqual(call[1], posargs[2])
def override_config(self, name, override, group=None):
"""Cleanly override CONF variables."""
CONF.set_override(name, override, group)
self.addCleanup(CONF.clear_override, name, group)

View File

@ -35,7 +35,7 @@ FakeMessage = collections.namedtuple(
class FakeNotifier(object): class FakeNotifier(object):
def __init__(self, transport, publisher_id, serializer=None): def __init__(self, transport, publisher_id=None, serializer=None):
self.transport = transport self.transport = transport
self.publisher_id = publisher_id self.publisher_id = publisher_id
for priority in ['debug', 'info', 'warn', 'error', 'critical']: for priority in ['debug', 'info', 'warn', 'error', 'critical']:

41
manila/tests/test_rpc.py Normal file
View File

@ -0,0 +1,41 @@
# Copyright 2017 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 ddt
import mock
from manila import rpc
from manila import test
@ddt.ddt
class RPCTestCase(test.TestCase):
def setUp(self):
super(RPCTestCase, self).setUp()
@ddt.data([], ['noop'], ['noop', 'noop'])
@mock.patch('oslo_messaging.JsonPayloadSerializer', wraps=True)
def test_init_no_notifications(self, driver, serializer_mock):
self.override_config('driver', driver,
group='oslo_messaging_notifications')
rpc.init(test.CONF)
self.assertEqual(rpc.utils.DO_NOTHING, rpc.NOTIFIER)
serializer_mock.assert_not_called()
@mock.patch.object(rpc, 'messaging')
def test_init_notifications(self, messaging_mock):
rpc.init(test.CONF)
self.assertTrue(messaging_mock.JsonPayloadSerializer.called)
self.assertTrue(messaging_mock.Notifier.called)
self.assertEqual(rpc.NOTIFIER, messaging_mock.Notifier.return_value)

View File

@ -16,6 +16,7 @@
import datetime import datetime
import errno import errno
import json
import socket import socket
import time import time
@ -803,3 +804,38 @@ class ConvertStrTestCase(test.TestCase):
self.assertEqual(0, utils.encodeutils.safe_encode.call_count) self.assertEqual(0, utils.encodeutils.safe_encode.call_count)
self.assertIsInstance(output_value, six.string_types) self.assertIsInstance(output_value, six.string_types)
self.assertEqual(six.text_type("binary_input"), output_value) self.assertEqual(six.text_type("binary_input"), output_value)
@ddt.ddt
class TestDisableNotifications(test.TestCase):
def test_do_nothing_getter(self):
"""Test any attribute will always return the same instance (self)."""
donothing = utils.DoNothing()
self.assertIs(donothing, donothing.anyname)
def test_do_nothing_caller(self):
"""Test calling the object will always return the same instance."""
donothing = utils.DoNothing()
self.assertIs(donothing, donothing())
def test_do_nothing_json_serializable(self):
"""Test calling the object will always return the same instance."""
donothing = utils.DoNothing()
self.assertEqual('""', json.dumps(donothing))
@utils.if_notifications_enabled
def _decorated_method(self):
return mock.sentinel.success
def test_if_notification_enabled_when_enabled(self):
"""Test method is called when notifications are enabled."""
result = self._decorated_method()
self.assertEqual(mock.sentinel.success, result)
@ddt.data([], ['noop'], ['noop', 'noop'])
def test_if_notification_enabled_when_disabled(self, driver):
"""Test method is not called when notifications are disabled."""
self.override_config('driver', driver,
group='oslo_messaging_notifications')
result = self._decorated_method()
self.assertEqual(utils.DO_NOTHING, result)

View File

@ -641,3 +641,35 @@ def wait_for_access_update(context, db, share_instance,
raise exception.ShareMigrationFailed(reason=msg) raise exception.ShareMigrationFailed(reason=msg)
else: else:
time.sleep(tries ** 2) time.sleep(tries ** 2)
class DoNothing(str):
"""Class that literrally does nothing.
We inherit from str in case it's called with json.dumps.
"""
def __call__(self, *args, **kwargs):
return self
def __getattr__(self, name):
return self
DO_NOTHING = DoNothing()
def notifications_enabled(conf):
"""Check if oslo notifications are enabled."""
notifications_driver = set(conf.oslo_messaging_notifications.driver)
return notifications_driver and notifications_driver != {'noop'}
def if_notifications_enabled(function):
"""Calls decorated method only if notifications are enabled."""
@functools.wraps(function)
def wrapped(*args, **kwargs):
if notifications_enabled(CONF):
return function(*args, **kwargs)
return DO_NOTHING
return wrapped