From 1eb6b8926a7a5ad442c5af6057c042999e2645f1 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Wed, 11 Aug 2021 09:13:55 +0000 Subject: [PATCH] Do not fail if the agent load is not bumped When a new network and its first subnet is created, the DHCP agent bumps the "load" parameter to reflect the number of networks handled. This "load" parameter is modified when: - As commented, when the first subnet of a network is created. The "load" value is bumped. - When periodically the DHCP agent sends the status, informing about the current number of networks handled. If during the subnet creation this "load" value is not updated, it will be in the next periodic update of the agent. This "load" value is used by the scheduler to equally distribute the objects to be managed by any agent type (DHCP agents manage networks). The bug refers to DHCP but is valid for any other agent. Conflicts: neutron/common/utils.py Change-Id: Ief402048d99d40b64d81fcf58eb2e39b1ba7ebbb Closes-Bug: #1939432 (cherry picked from commit 668b1cc652f076e555ef1fc1289684367159186a) (cherry picked from commit 816aca60b90b89038863d6974b5a9e0ee8983424) --- neutron/common/utils.py | 22 ++++++++++++++++++++++ neutron/scheduler/base_resource_filter.py | 4 ++++ neutron/tests/unit/common/test_utils.py | 22 ++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/neutron/common/utils.py b/neutron/common/utils.py index 1ace8c8f0f9..ac47746f2d9 100644 --- a/neutron/common/utils.py +++ b/neutron/common/utils.py @@ -965,3 +965,25 @@ def with_metaclass(meta, *bases): return meta(name, bases, d) return metaclass('temporary_class', None, {}) + + +def skip_exceptions(exceptions): + """Decorator to catch and hide any provided exception in the argument""" + + # NOTE(ralonsoh): could be rehomed to neutron-lib. + if not isinstance(exceptions, list): + exceptions = [exceptions] + + def decorator(function): + @functools.wraps(function) + def wrapper(*args, **kwargs): + try: + return function(*args, **kwargs) + except Exception as exc: + with excutils.save_and_reraise_exception() as ctx: + if issubclass(type(exc), tuple(exceptions)): + LOG.info('Skipped exception %s when calling method %s', + ctx.value.__repr__(), function.__repr__()) + ctx.reraise = False + return wrapper + return decorator diff --git a/neutron/scheduler/base_resource_filter.py b/neutron/scheduler/base_resource_filter.py index c597958c653..133ce7271a4 100644 --- a/neutron/scheduler/base_resource_filter.py +++ b/neutron/scheduler/base_resource_filter.py @@ -16,6 +16,9 @@ import abc from neutron_lib.db import api as db_api +from oslo_db import exception as db_exc + +from neutron.common import utils as n_utils class BaseResourceFilter(object, metaclass=abc.ABCMeta): @@ -24,6 +27,7 @@ class BaseResourceFilter(object, metaclass=abc.ABCMeta): def filter_agents(self, plugin, context, resource): """Return the agents that can host the resource.""" + @n_utils.skip_exceptions(db_exc.DBError) def bind(self, context, agents, resource_id, force_scheduling=False): """Bind the resource to the agents.""" with db_api.CONTEXT_WRITER.using(context): diff --git a/neutron/tests/unit/common/test_utils.py b/neutron/tests/unit/common/test_utils.py index 688dd15f1c2..238c4645592 100644 --- a/neutron/tests/unit/common/test_utils.py +++ b/neutron/tests/unit/common/test_utils.py @@ -603,3 +603,25 @@ class SingletonDecoratorTestCase(base.BaseTestCase): instance_2 = _TestSingletonClass() self.assertEqual(instance_1.__hash__(), instance_2.__hash__()) self.assertEqual('value1', instance_2.variable) + + +class SkipDecoratorTestCase(base.BaseTestCase): + + def test_skip_exception(self): + @utils.skip_exceptions(AttributeError) + def raise_attribute_error_single_exception(): + raise AttributeError() + + @utils.skip_exceptions([AttributeError, IndexError]) + def raise_attribute_error_exception_list(): + raise AttributeError() + + raise_attribute_error_single_exception() + raise_attribute_error_exception_list() + + def test_skip_exception_fail(self): + @utils.skip_exceptions(IndexError) + def raise_attribute_error(): + raise AttributeError() + + self.assertRaises(AttributeError, raise_attribute_error)