From f4741011eac18bd4fe76f90da513ba9b025afdd1 Mon Sep 17 00:00:00 2001 From: Roey Chen Date: Sat, 21 Feb 2015 03:51:40 -0800 Subject: [PATCH] Using python retrying module Change-Id: I863e064b0802d38038d83fdcf943fd82af5f4422 Signed-off-by: Roey Chen --- requirements.txt | 1 + .../neutron/plugins/vmware/vshield/vcns.py | 26 +++------ .../tests/unit/vmware/test_nsx_misc.py | 53 +++++++++++++++++++ 3 files changed, 61 insertions(+), 19 deletions(-) create mode 100644 vmware_nsx/neutron/tests/unit/vmware/test_nsx_misc.py diff --git a/requirements.txt b/requirements.txt index 8edb101bcc..dd2898f4f3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,7 @@ pbr>=0.6,!=0.7,<1.0 eventlet>=0.15.2 httplib2>=0.7.5 netaddr>=0.7.12 +retrying>=1.2.3,!=1.3.0 # Apache-2.0 SQLAlchemy>=0.9.7,<=0.9.99 six>=1.7.0 stevedore>=1.1.0 # Apache-2.0 diff --git a/vmware_nsx/neutron/plugins/vmware/vshield/vcns.py b/vmware_nsx/neutron/plugins/vmware/vshield/vcns.py index a0055eadff..1cd447f0b5 100644 --- a/vmware_nsx/neutron/plugins/vmware/vshield/vcns.py +++ b/vmware_nsx/neutron/plugins/vmware/vshield/vcns.py @@ -14,11 +14,9 @@ # License for the specific language governing permissions and limitations # under the License. -import functools -import time - from oslo.config import cfg from oslo.serialization import jsonutils +import retrying import xml.etree.ElementTree as et from neutron.openstack.common import log as logging @@ -60,22 +58,12 @@ DHCP_SERVICE = "dhcp/config" DHCP_BINDING_RESOURCE = "bindings" -def retry_upon_exception(exception, delay=0.5, max_delay=2): - def retry_decorator(f): - @functools.wraps(f) - def retry_wrapper(*args, **kwargs): - retries = max(cfg.CONF.nsxv.retries, 1) - for attempt in range(1, retries + 1): - try: - return f(*args, **kwargs) - except exception as e: - if attempt == retries: - LOG.info("NSXv: API called failed") - raise e - tts = (2 ** (attempt - 1)) * delay - time.sleep(min(tts, max_delay)) - return retry_wrapper - return retry_decorator +def retry_upon_exception(exc, delay=500, max_delay=2000, + max_attempts=cfg.CONF.nsxv.retries): + return retrying.retry(retry_on_exception=lambda e: isinstance(e, exc), + wait_exponential_multiplier=delay, + wait_exponential_max=max_delay, + stop_max_attempt_number=max_attempts) class Vcns(object): diff --git a/vmware_nsx/neutron/tests/unit/vmware/test_nsx_misc.py b/vmware_nsx/neutron/tests/unit/vmware/test_nsx_misc.py new file mode 100644 index 0000000000..595d3d503f --- /dev/null +++ b/vmware_nsx/neutron/tests/unit/vmware/test_nsx_misc.py @@ -0,0 +1,53 @@ +# Copyright (c) 2014 VMware. +# +# 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. + +from neutron.tests import base + +from vmware_nsx.neutron.plugins.vmware.vshield.common import exceptions +from vmware_nsx.neutron.plugins.vmware.vshield import vcns + + +def raise_until_attempt(attempt, exception): + def raises_until(): + if raises_until.current_attempt < attempt: + raises_until.current_attempt += 1 + raise exception + else: + return raises_until.current_attempt + raises_until.current_attempt = 1 + return raises_until + + +class TestMisc(base.BaseTestCase): + def test_retry_on_exception_one_attempt(self): + success_on_first_attempt = raise_until_attempt( + 1, exceptions.RequestBad(uri='', response='')) + should_return_one = vcns.retry_upon_exception( + exceptions.RequestBad, max_attempts=1)(success_on_first_attempt) + self.assertEqual(1, should_return_one()) + + def test_retry_on_exception_five_attempts(self): + success_on_fifth_attempt = raise_until_attempt( + 5, exceptions.RequestBad(uri='', response='')) + should_return_five = vcns.retry_upon_exception( + exceptions.RequestBad, max_attempts=10)(success_on_fifth_attempt) + self.assertEqual(5, should_return_five()) + + def test_retry_on_exception_exceed_attempts(self): + success_on_fifth_attempt = raise_until_attempt( + 5, exceptions.RequestBad(uri='', response='')) + should_raise = vcns.retry_upon_exception( + exceptions.RequestBad, max_attempts=4)(success_on_fifth_attempt) + self.assertRaises(exceptions.RequestBad, should_raise)