diff --git a/neutron/agent/ovsdb/native/idlutils.py b/neutron/agent/ovsdb/native/idlutils.py index def2d0b1f55..4198c90c63c 100644 --- a/neutron/agent/ovsdb/native/idlutils.py +++ b/neutron/agent/ovsdb/native/idlutils.py @@ -18,7 +18,6 @@ import time import uuid from neutron_lib import exceptions -from oslo_utils import excutils from ovs.db import idl from ovs import jsonrpc from ovs import poller @@ -118,24 +117,25 @@ def _get_schema_helper(connection, schema_name): return idl.SchemaHelper(None, resp.result) -def get_schema_helper(connection, schema_name, retry=True): +def get_schema_helper(connection, schema_name, retry=True, + try_add_manager=True): try: return _get_schema_helper(connection, schema_name) except Exception: - with excutils.save_and_reraise_exception(reraise=False) as ctx: - if not retry: - ctx.reraise = True - # We may have failed due to set-manager not being called + if not retry: + raise + # We may have failed due to set-manager not being called + if try_add_manager: helpers.enable_connection_uri(connection, set_timeout=True) - # There is a small window for a race, so retry up to a second - @tenacity.retry(wait=tenacity.wait_exponential(multiplier=0.01), - stop=tenacity.stop_after_delay(1), - reraise=True) - def do_get_schema_helper(): - return _get_schema_helper(connection, schema_name) + # There is a small window for a race, so retry up to a second + @tenacity.retry(wait=tenacity.wait_exponential(multiplier=0.01), + stop=tenacity.stop_after_delay(1), + reraise=True) + def do_get_schema_helper(): + return _get_schema_helper(connection, schema_name) - return do_get_schema_helper() + return do_get_schema_helper() def wait_for_change(_idl, timeout, seqno=None): diff --git a/neutron/tests/unit/agent/ovsdb/native/test_idlutils.py b/neutron/tests/unit/agent/ovsdb/native/test_idlutils.py index 54dff1ce737..030486a7f24 100644 --- a/neutron/tests/unit/agent/ovsdb/native/test_idlutils.py +++ b/neutron/tests/unit/agent/ovsdb/native/test_idlutils.py @@ -154,3 +154,51 @@ class TestIdlUtils(base.BaseTestCase): mock.sentinel.table_name, FAKE_RECORD) self.assertEqual(mock.sentinel.row_value, res) + + @mock.patch.object(idlutils.helpers, 'enable_connection_uri') + @mock.patch.object(idlutils, '_get_schema_helper') + def test_get_schema_helper_succeed_once(self, + mock_get_schema_helper, + mock_enable_conn): + mock_get_schema_helper.return_value = mock.Mock() + + idlutils.get_schema_helper(mock.Mock(), mock.Mock()) + self.assertEqual(1, mock_get_schema_helper.call_count) + self.assertEqual(0, mock_enable_conn.call_count) + + @mock.patch.object(idlutils.helpers, 'enable_connection_uri') + @mock.patch.object(idlutils, '_get_schema_helper') + def test_get_schema_helper_fail_and_then_succeed(self, + mock_get_schema_helper, + mock_enable_conn): + # raise until 3rd retry attempt + mock_get_schema_helper.side_effect = [Exception(), Exception(), + mock.Mock()] + + idlutils.get_schema_helper(mock.Mock(), mock.Mock()) + self.assertEqual(3, mock_get_schema_helper.call_count) + self.assertEqual(1, mock_enable_conn.call_count) + + @mock.patch.object(idlutils.helpers, 'enable_connection_uri') + @mock.patch.object(idlutils, '_get_schema_helper') + def test_get_schema_helper_not_add_manager_and_timeout( + self, mock_get_schema_helper, mock_enable_conn): + # raise always + mock_get_schema_helper.side_effect = RuntimeError() + + self.assertRaises(RuntimeError, idlutils.get_schema_helper, + mock.Mock(), mock.Mock(), retry=True, + try_add_manager=False) + self.assertEqual(8, mock_get_schema_helper.call_count) + self.assertEqual(0, mock_enable_conn.call_count) + + @mock.patch.object(idlutils.helpers, 'enable_connection_uri') + @mock.patch.object(idlutils, '_get_schema_helper') + def test_get_schema_helper_not_retry( + self, mock_get_schema_helper, mock_enable_conn): + # raise always + mock_get_schema_helper.side_effect = RuntimeError() + + self.assertRaises(RuntimeError, idlutils.get_schema_helper, + mock.Mock(), mock.Mock(), retry=False) + self.assertEqual(1, mock_get_schema_helper.call_count)