diff --git a/manila/rpc.py b/manila/rpc.py index 936d594bfa..8f11d5ea16 100644 --- a/manila/rpc.py +++ b/manila/rpc.py @@ -32,6 +32,7 @@ from oslo_serialization import jsonutils import manila.context import manila.exception +from manila import utils CONF = cfg.CONF TRANSPORT = None @@ -53,9 +54,13 @@ def init(conf): conf, allowed_remote_exmods=exmods) - serializer = RequestContextSerializer(JsonPayloadSerializer()) - NOTIFIER = messaging.Notifier(NOTIFICATION_TRANSPORT, - serializer=serializer) + if utils.notifications_enabled(conf): + json_serializer = messaging.JsonPayloadSerializer() + serializer = RequestContextSerializer(json_serializer) + NOTIFIER = messaging.Notifier(NOTIFICATION_TRANSPORT, + serializer=serializer) + else: + NOTIFIER = utils.DO_NOTHING def initialized(): @@ -141,6 +146,7 @@ def get_server(target, endpoints, serializer=None): access_policy=access_policy) +@utils.if_notifications_enabled def get_notifier(service=None, host=None, publisher_id=None): assert NOTIFIER is not None if not publisher_id: diff --git a/manila/share/utils.py b/manila/share/utils.py index 975f7afc0a..2d42a844a3 100644 --- a/manila/share/utils.py +++ b/manila/share/utils.py @@ -20,6 +20,7 @@ from oslo_config import cfg from manila.common import constants from manila import rpc +from manila import utils DEFAULT_POOL_NAME = '_pool0' CONF = cfg.CONF @@ -109,6 +110,7 @@ def cast_access_object_to_dict_in_readonly(rules): return dict_rules +@utils.if_notifications_enabled def notify_about_share_usage(context, share, share_instance, event_suffix, extra_usage_info=None, host=None): diff --git a/manila/test.py b/manila/test.py index cdd1dcc9b0..baef99fbbc 100644 --- a/manila/test.py +++ b/manila/test.py @@ -30,6 +30,7 @@ from oslo_concurrency import lockutils from oslo_config import cfg from oslo_config import fixture as config_fixture import oslo_i18n +import oslo_messaging from oslo_messaging import conffixture as messaging_conffixture from oslo_utils import uuidutils import oslotest.base as base_test @@ -140,6 +141,11 @@ class TestCase(base_test.BaseTestCase): self.messaging_conf.transport_driver = 'fake' self.messaging_conf.response_timeout = 15 self.useFixture(self.messaging_conf) + + oslo_messaging.get_notification_transport(CONF) + self.override_config('driver', ['test'], + group='oslo_messaging_notifications') + rpc.init(CONF) 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[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) diff --git a/manila/tests/fake_notifier.py b/manila/tests/fake_notifier.py index 8ce1fadf06..61452e6e32 100644 --- a/manila/tests/fake_notifier.py +++ b/manila/tests/fake_notifier.py @@ -35,7 +35,7 @@ FakeMessage = collections.namedtuple( class FakeNotifier(object): - def __init__(self, transport, publisher_id, serializer=None): + def __init__(self, transport, publisher_id=None, serializer=None): self.transport = transport self.publisher_id = publisher_id for priority in ['debug', 'info', 'warn', 'error', 'critical']: diff --git a/manila/tests/test_rpc.py b/manila/tests/test_rpc.py new file mode 100644 index 0000000000..9cd5d0d3d6 --- /dev/null +++ b/manila/tests/test_rpc.py @@ -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) diff --git a/manila/tests/test_utils.py b/manila/tests/test_utils.py index fb4dc33501..31e6217b7f 100644 --- a/manila/tests/test_utils.py +++ b/manila/tests/test_utils.py @@ -16,6 +16,7 @@ import datetime import errno +import json import socket import time @@ -803,3 +804,38 @@ class ConvertStrTestCase(test.TestCase): self.assertEqual(0, utils.encodeutils.safe_encode.call_count) self.assertIsInstance(output_value, six.string_types) 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) diff --git a/manila/utils.py b/manila/utils.py index c79a95b913..3be8e74886 100644 --- a/manila/utils.py +++ b/manila/utils.py @@ -641,3 +641,35 @@ def wait_for_access_update(context, db, share_instance, raise exception.ShareMigrationFailed(reason=msg) else: 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