diff --git a/nova/api/openstack/wsgi_app.py b/nova/api/openstack/wsgi_app.py index bad600a0e08d..3fef2df2bc57 100644 --- a/nova/api/openstack/wsgi_app.py +++ b/nova/api/openstack/wsgi_app.py @@ -23,13 +23,11 @@ from nova import context from nova import exception from nova import objects from nova import service -from nova import utils CONF = cfg.CONF CONFIG_FILES = ['api-paste.ini', 'nova.conf'] -utils.monkey_patch() objects.register_all() diff --git a/nova/cmd/api.py b/nova/cmd/api.py index 410c40b5f0f0..2080b0d5e81c 100644 --- a/nova/cmd/api.py +++ b/nova/cmd/api.py @@ -31,7 +31,6 @@ from nova import config from nova import exception from nova import objects from nova import service -from nova import utils from nova import version CONF = nova.conf.CONF @@ -40,7 +39,6 @@ CONF = nova.conf.CONF def main(): config.parse_args(sys.argv) logging.setup(CONF, "nova") - utils.monkey_patch() objects.register_all() gmr_opts.set_defaults(CONF) if 'osapi_compute' in CONF.enabled_apis: diff --git a/nova/cmd/api_metadata.py b/nova/cmd/api_metadata.py index 3709211260e4..493f3e0c8e9c 100644 --- a/nova/cmd/api_metadata.py +++ b/nova/cmd/api_metadata.py @@ -28,7 +28,6 @@ from nova import config from nova import objects from nova.objects import base as objects_base from nova import service -from nova import utils from nova import version @@ -38,7 +37,6 @@ CONF = nova.conf.CONF def main(): config.parse_args(sys.argv) logging.setup(CONF, "nova") - utils.monkey_patch() objects.register_all() gmr_opts.set_defaults(CONF) diff --git a/nova/cmd/api_os_compute.py b/nova/cmd/api_os_compute.py index bfb530c1c803..f7d3beb10c6b 100644 --- a/nova/cmd/api_os_compute.py +++ b/nova/cmd/api_os_compute.py @@ -26,7 +26,6 @@ import nova.conf from nova import config from nova import objects from nova import service -from nova import utils from nova import version @@ -36,7 +35,6 @@ CONF = nova.conf.CONF def main(): config.parse_args(sys.argv) logging.setup(CONF, "nova") - utils.monkey_patch() objects.register_all() gmr_opts.set_defaults(CONF) # NOTE(mriedem): This is needed for caching the nova-compute service diff --git a/nova/cmd/cells.py b/nova/cmd/cells.py index 0c18496c6212..87734babef05 100644 --- a/nova/cmd/cells.py +++ b/nova/cmd/cells.py @@ -26,7 +26,6 @@ import nova.conf from nova import config from nova import objects from nova import service -from nova import utils from nova import version CONF = nova.conf.CONF @@ -36,7 +35,6 @@ LOG = logging.getLogger('nova.cells') def main(): config.parse_args(sys.argv) logging.setup(CONF, 'nova') - utils.monkey_patch() objects.register_all() gmr_opts.set_defaults(CONF) diff --git a/nova/cmd/compute.py b/nova/cmd/compute.py index d9f14430f14e..01fd20de2e54 100644 --- a/nova/cmd/compute.py +++ b/nova/cmd/compute.py @@ -43,7 +43,6 @@ def main(): config.parse_args(sys.argv) logging.setup(CONF, 'nova') priv_context.init(root_helper=shlex.split(utils.get_root_helper())) - utils.monkey_patch() objects.register_all() gmr_opts.set_defaults(CONF) # Ensure os-vif objects are registered and plugins loaded diff --git a/nova/cmd/conductor.py b/nova/cmd/conductor.py index 4d58b5864cd7..16847c2e5610 100644 --- a/nova/cmd/conductor.py +++ b/nova/cmd/conductor.py @@ -26,7 +26,6 @@ import nova.conf from nova import config from nova import objects from nova import service -from nova import utils from nova import version CONF = nova.conf.CONF @@ -35,7 +34,6 @@ CONF = nova.conf.CONF def main(): config.parse_args(sys.argv) logging.setup(CONF, "nova") - utils.monkey_patch() objects.register_all() gmr_opts.set_defaults(CONF) objects.Service.enable_min_version_cache() diff --git a/nova/cmd/network.py b/nova/cmd/network.py index ff1273cda91a..92c0bb28f390 100644 --- a/nova/cmd/network.py +++ b/nova/cmd/network.py @@ -30,7 +30,6 @@ from nova.network import rpcapi as network_rpcapi from nova import objects from nova.objects import base as objects_base from nova import service -from nova import utils from nova import version CONF = nova.conf.CONF @@ -46,7 +45,6 @@ def main(): 'except as required for CellsV1 deployments.') return 1 - utils.monkey_patch() objects.register_all() gmr_opts.set_defaults(CONF) diff --git a/nova/cmd/scheduler.py b/nova/cmd/scheduler.py index dafec005b48e..3ea220d4d99e 100644 --- a/nova/cmd/scheduler.py +++ b/nova/cmd/scheduler.py @@ -28,7 +28,6 @@ from nova import config from nova import objects from nova.scheduler import rpcapi as scheduler_rpcapi from nova import service -from nova import utils from nova import version CONF = nova.conf.CONF @@ -37,7 +36,6 @@ CONF = nova.conf.CONF def main(): config.parse_args(sys.argv) logging.setup(CONF, "nova") - utils.monkey_patch() objects.register_all() gmr_opts.set_defaults(CONF) objects.Service.enable_min_version_cache() diff --git a/nova/conf/base.py b/nova/conf/base.py index d8ca1f56d6b4..b2fbb9258b9f 100644 --- a/nova/conf/base.py +++ b/nova/conf/base.py @@ -60,48 +60,6 @@ entry. cfg.StrOpt( 'tempdir', help='Explicitly specify the temporary working directory.'), - cfg.BoolOpt( - 'monkey_patch', - default=False, - deprecated_for_removal=True, - deprecated_since='17.0.0', - deprecated_reason=""" -Monkey patching nova is not tested, not supported, and is a barrier -for interoperability. -""", - help=""" -Determine if monkey patching should be applied. - -Related options: - -* ``monkey_patch_modules``: This must have values set for this option to - have any effect -"""), - cfg.ListOpt( - 'monkey_patch_modules', - default=['nova.compute.api:nova.notifications.notify_decorator'], - deprecated_for_removal=True, - deprecated_since='17.0.0', - deprecated_reason=""" -Monkey patching nova is not tested, not supported, and is a barrier -for interoperability. -""", - help=""" -List of modules/decorators to monkey patch. - -This option allows you to patch a decorator for all functions in specified -modules. - -Possible values: - -* nova.compute.api:nova.notifications.notify_decorator -* [...] - -Related options: - -* ``monkey_patch``: This must be set to ``True`` for this option to - have any effect -"""), ] diff --git a/nova/conf/notifications.py b/nova/conf/notifications.py index 13ee9f3c3718..91ed87966f39 100644 --- a/nova/conf/notifications.py +++ b/nova/conf/notifications.py @@ -57,32 +57,6 @@ Possible values: deprecated_group='DEFAULT', deprecated_name='default_notification_level', help="Default notification level for outgoing notifications."), - - cfg.StrOpt( - 'default_publisher_id', - default='$host', - deprecated_group='DEFAULT', - deprecated_for_removal=True, - deprecated_since='17.0.0', - deprecated_reason=""" -This option is only used when ``monkey_patch=True`` and -``monkey_patch_modules`` is configured to specify the legacy notify_decorator. -Since the monkey_patch and monkey_patch_modules options are deprecated, this -option is also deprecated. -""", - help=""" -Default publisher_id for outgoing notifications. If you consider routing -notifications using different publisher, change this value accordingly. - -Possible values: - -* Defaults to the current hostname of this host, but it can be any valid - oslo.messaging publisher_id - -Related options: - -* host - Hostname, FQDN or IP address of this host. -"""), cfg.StrOpt( 'notification_format', choices=['unversioned', 'versioned', 'both'], diff --git a/nova/notifications/__init__.py b/nova/notifications/__init__.py index ff27fc2457df..42d083bb88f5 100644 --- a/nova/notifications/__init__.py +++ b/nova/notifications/__init__.py @@ -21,6 +21,5 @@ from nova.notifications.base import audit_period_bounds # noqa from nova.notifications.base import bandwidth_usage # noqa from nova.notifications.base import image_meta # noqa from nova.notifications.base import info_from_instance # noqa -from nova.notifications.base import notify_decorator # noqa from nova.notifications.base import send_update # noqa from nova.notifications.base import send_update_with_states # noqa diff --git a/nova/notifications/base.py b/nova/notifications/base.py index 17640ff5ed8c..0bccc5cd9eb2 100644 --- a/nova/notifications/base.py +++ b/nova/notifications/base.py @@ -21,7 +21,6 @@ the system. import datetime from keystoneauth1 import exceptions as ks_exc -from oslo_context import context as common_context from oslo_log import log from oslo_utils import excutils from oslo_utils import timeutils @@ -46,41 +45,6 @@ LOG = log.getLogger(__name__) CONF = nova.conf.CONF -# TODO(mriedem): Remove this when CONF.monkey_patch, CONF.monkey_patch_modules -# and CONF.default_publisher_id are removed in Rocky. -def notify_decorator(name, fn): - """Decorator for notify which is used from utils.monkey_patch(). - - :param name: name of the function - :param fn: - object of the function - :returns: fn -- 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) or - common_context.get_current() or - nova.context.RequestContext()) - - notifier = rpc.get_notifier('api', publisher_id=( - CONF.notifications.default_publisher_id or CONF.host)) - method = getattr(notifier, - CONF.notifications.default_level.lower(), - notifier.info) - method(ctxt, name, body) - - return fn(*args, **kwarg) - return wrapped_func - - def send_update(context, old_instance, new_instance, service="compute", host=None): """Send compute.instance.update notification to report any changes occurred diff --git a/nova/tests/unit/cmd/test_cmd_db_blocks.py b/nova/tests/unit/cmd/test_cmd_db_blocks.py index 80ad457354ae..8856ca2a50c5 100644 --- a/nova/tests/unit/cmd/test_cmd_db_blocks.py +++ b/nova/tests/unit/cmd/test_cmd_db_blocks.py @@ -33,10 +33,9 @@ def restore_db(): class ComputeMainTest(test.NoDBTestCase): - @mock.patch('nova.utils.monkey_patch') @mock.patch('nova.conductor.api.API.wait_until_ready') @mock.patch('oslo_reports.guru_meditation_report') - def _call_main(self, mod, gmr, cond, patch): + def _call_main(self, mod, gmr, cond): @mock.patch.object(mod, 'config') @mock.patch.object(mod, 'service') def run_main(serv, conf): diff --git a/nova/tests/unit/monkey_patch_example/__init__.py b/nova/tests/unit/monkey_patch_example/__init__.py deleted file mode 100644 index bf0a9e4214bb..000000000000 --- a/nova/tests/unit/monkey_patch_example/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -"""Example Module for testing utils.monkey_patch().""" - - -CALLED_FUNCTION = [] - - -def example_decorator(name, function): - """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): - CALLED_FUNCTION.append(name) - return function(*args, **kwarg) - return wrapped_func diff --git a/nova/tests/unit/monkey_patch_example/example_a.py b/nova/tests/unit/monkey_patch_example/example_a.py deleted file mode 100644 index 3844766ea7e5..000000000000 --- a/nova/tests/unit/monkey_patch_example/example_a.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -"""Example Module A for testing utils.monkey_patch().""" - - -def example_function_a(): - return 'Example function' - - -class ExampleClassA(object): - def example_method(self): - return 'Example method' - - def example_method_add(self, arg1, arg2): - return arg1 + arg2 diff --git a/nova/tests/unit/monkey_patch_example/example_b.py b/nova/tests/unit/monkey_patch_example/example_b.py deleted file mode 100644 index 52803377fc10..000000000000 --- a/nova/tests/unit/monkey_patch_example/example_b.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2011 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Example Module B for testing utils.monkey_patch().""" - - -def example_function_b(): - return 'Example function' - - -class ExampleClassB(object): - def example_method(self): - return 'Example method' - - def example_method_add(self, arg1, arg2): - return arg1 + arg2 diff --git a/nova/tests/unit/test_notifications.py b/nova/tests/unit/test_notifications.py index c41d0daaa0b1..c77f0183a8ec 100644 --- a/nova/tests/unit/test_notifications.py +++ b/nova/tests/unit/test_notifications.py @@ -20,7 +20,6 @@ import datetime import mock from oslo_config import cfg -from oslo_context import context as o_context from oslo_context import fixture as o_fixture from oslo_utils import timeutils @@ -519,26 +518,6 @@ class NotificationsTestCase(test.TestCase): def _decorated_function(self, arg1, arg2): self.decorated_function_called = True - def test_notify_decorator(self): - func_name = self._decorated_function.__name__ - - # Decorated with notify_decorator like monkey_patch - self._decorated_function = notifications.notify_decorator( - func_name, - self._decorated_function) - - ctxt = o_context.RequestContext() - - self._decorated_function(1, ctxt) - - self.assertEqual(1, len(fake_notifier.NOTIFICATIONS)) - n = fake_notifier.NOTIFICATIONS[0] - self.assertEqual(n.priority, 'INFO') - self.assertEqual(n.event_type, func_name) - self.assertEqual(n.context, ctxt) - self.assertTrue(self.decorated_function_called) - self.assertEqual(CONF.host, n.publisher_id) - class NotificationsFormatTestCase(test.NoDBTestCase): diff --git a/nova/tests/unit/test_utils.py b/nova/tests/unit/test_utils.py index 82b59ceef114..d45078662b07 100644 --- a/nova/tests/unit/test_utils.py +++ b/nova/tests/unit/test_utils.py @@ -14,7 +14,6 @@ import datetime import hashlib -import importlib import os import os.path import tempfile @@ -36,7 +35,6 @@ from oslo_utils import fixture as utils_fixture from oslo_utils import units import six -import nova from nova import context from nova import exception from nova.objects import base as obj_base @@ -457,74 +455,6 @@ Exit code: -2''') mock.call(['a', '1'], None)]) -class MonkeyPatchTestCase(test.NoDBTestCase): - """Unit test for utils.monkey_patch().""" - def setUp(self): - super(MonkeyPatchTestCase, self).setUp() - self.example_package = 'nova.tests.unit.monkey_patch_example.' - self.flags( - monkey_patch=True, - monkey_patch_modules=[self.example_package + 'example_a' + ':' - + self.example_package + 'example_decorator']) - - def test_monkey_patch(self): - utils.monkey_patch() - nova.tests.unit.monkey_patch_example.CALLED_FUNCTION = [] - from nova.tests.unit.monkey_patch_example import example_a - from nova.tests.unit.monkey_patch_example import example_b - - self.assertEqual('Example function', example_a.example_function_a()) - exampleA = example_a.ExampleClassA() - exampleA.example_method() - ret_a = exampleA.example_method_add(3, 5) - self.assertEqual(ret_a, 8) - - self.assertEqual('Example function', example_b.example_function_b()) - exampleB = example_b.ExampleClassB() - exampleB.example_method() - ret_b = exampleB.example_method_add(3, 5) - - self.assertEqual(ret_b, 8) - package_a = self.example_package + 'example_a.' - self.assertIn(package_a + 'example_function_a', - nova.tests.unit.monkey_patch_example.CALLED_FUNCTION) - - self.assertIn(package_a + 'ExampleClassA.example_method', - nova.tests.unit.monkey_patch_example.CALLED_FUNCTION) - self.assertIn(package_a + 'ExampleClassA.example_method_add', - nova.tests.unit.monkey_patch_example.CALLED_FUNCTION) - package_b = self.example_package + 'example_b.' - self.assertNotIn(package_b + 'example_function_b', - nova.tests.unit.monkey_patch_example.CALLED_FUNCTION) - self.assertNotIn(package_b + 'ExampleClassB.example_method', - nova.tests.unit.monkey_patch_example.CALLED_FUNCTION) - self.assertNotIn(package_b + 'ExampleClassB.example_method_add', - nova.tests.unit.monkey_patch_example.CALLED_FUNCTION) - - -class MonkeyPatchDefaultTestCase(test.NoDBTestCase): - """Unit test for default monkey_patch_modules value.""" - - def setUp(self): - super(MonkeyPatchDefaultTestCase, self).setUp() - self.flags( - monkey_patch=True) - - def test_monkey_patch_default_mod(self): - # monkey_patch_modules is defined to be - # : - # Here we check that both parts of the default values are - # valid - for module in CONF.monkey_patch_modules: - m = module.split(':', 1) - # Check we can import the module to be patched - importlib.import_module(m[0]) - # check the decorator is valid - decorator_name = m[1].rsplit('.', 1) - decorator_module = importlib.import_module(decorator_name[0]) - getattr(decorator_module, decorator_name[1]) - - class AuditPeriodTest(test.NoDBTestCase): def setUp(self): diff --git a/nova/utils.py b/nova/utils.py index 18d633a0579f..55865b9dff23 100644 --- a/nova/utils.py +++ b/nova/utils.py @@ -24,11 +24,9 @@ import functools import hashlib import inspect import os -import pyclbr import random import re import shutil -import sys import tempfile import time @@ -469,55 +467,6 @@ def format_remote_path(host, path): return "%s:%s" % (safe_ip_format(host), path) -# TODO(mriedem): Remove this in Rocky. -def monkey_patch(): - """DEPRECATED: If the CONF.monkey_patch set as True, - this function patches a decorator - for all functions in specified modules. - You can set decorators for each modules - using CONF.monkey_patch_modules. - The format is "Module path:Decorator function". - Example: - 'nova.api.ec2.cloud:nova.notifications.notify_decorator' - - Parameters of the decorator is as follows. - (See nova.notifications.notify_decorator) - - name - name of the function - function - object of the function - """ - # If CONF.monkey_patch is not True, this function do nothing. - if not CONF.monkey_patch: - return - LOG.warning('Monkey patching nova is deprecated for removal.') - if six.PY2: - is_method = inspect.ismethod - else: - def is_method(obj): - # Unbound methods became regular functions on Python 3 - return inspect.ismethod(obj) or inspect.isfunction(obj) - # Get list of modules and decorators - for module_and_decorator in CONF.monkey_patch_modules: - module, decorator_name = module_and_decorator.split(':') - # import decorator function - decorator = importutils.import_class(decorator_name) - __import__(module) - # Retrieve module information using pyclbr - module_data = pyclbr.readmodule_ex(module) - for key, value in module_data.items(): - # set the decorator for the class methods - if isinstance(value, pyclbr.Class): - clz = importutils.import_class("%s.%s" % (module, key)) - for method, func in inspect.getmembers(clz, is_method): - setattr(clz, method, - decorator("%s.%s.%s" % (module, key, method), func)) - # set the decorator for the function - if isinstance(value, pyclbr.Function): - func = importutils.import_class("%s.%s" % (module, key)) - setattr(sys.modules[module], key, - decorator("%s.%s" % (module, key), func)) - - def make_dev_path(dev, partition=None, base='/dev'): """Return a path to a particular device. diff --git a/releasenotes/notes/remove-monkey-patch-conf-220ea611d4ff348e.yaml b/releasenotes/notes/remove-monkey-patch-conf-220ea611d4ff348e.yaml new file mode 100644 index 000000000000..8a73a1f68ba7 --- /dev/null +++ b/releasenotes/notes/remove-monkey-patch-conf-220ea611d4ff348e.yaml @@ -0,0 +1,14 @@ +--- +upgrade: + - | + The following configuration options were deprecated for removal in the + 17.0.0 Queens release and have now been removed: + + - ``[DEFAULT]/monkey_patch`` + - ``[DEFAULT]/monkey_patch_modules`` + - ``[notifications]/default_publisher_id`` + + Monkey patching nova is not tested, not supported, and is a barrier to + interoperability. If you have code which relies on monkey patching + decorators, for example, for notifications, please propose those changes + upstream. diff --git a/tools/xenserver/destroy_cached_images.py b/tools/xenserver/destroy_cached_images.py index c9025e9423ae..9f095a1b5c19 100644 --- a/tools/xenserver/destroy_cached_images.py +++ b/tools/xenserver/destroy_cached_images.py @@ -44,7 +44,6 @@ if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'nova', '__init__.py')): import nova.conf from nova import config -from nova import utils from nova.virt.xenapi import vm_utils destroy_opts = [ @@ -66,7 +65,6 @@ CONF.register_cli_opts(destroy_opts) def main(): config.parse_args(sys.argv) - utils.monkey_patch() _session = session.XenAPISession(CONF.xenserver.connection_url, CONF.xenserver.connection_username,