From ff61b5fb9d7a20836cd6da3d9bf7fa9c824efa10 Mon Sep 17 00:00:00 2001 From: Mark Chappell Date: Thu, 4 Aug 2022 21:04:46 +0200 Subject: [PATCH] Bump CloudRetry.backoff deprecation to 6.0.0 (#951) Bump CloudRetry.backoff deprecation to 6.0.0 SUMMARY We originally slated CloudRetry.backoff to go away with 4.0.0, bump it out to 6.0.0 since we missed the cut-off (no hurry) ISSUE TYPE Feature Pull Request COMPONENT NAME plugins/module_utils/cloud.py ADDITIONAL INFORMATION Reviewed-by: Alina Buzachis (cherry picked from commit 1a4595a59318062dfbc6ec89c7a2e5d096e319bb) --- changelogs/fragments/951-cloudretry.yml | 2 + plugins/module_utils/cloud.py | 11 ++++- tests/unit/module_utils/test_cloud.py | 55 ++++++++++++++----------- 3 files changed, 43 insertions(+), 25 deletions(-) create mode 100644 changelogs/fragments/951-cloudretry.yml diff --git a/changelogs/fragments/951-cloudretry.yml b/changelogs/fragments/951-cloudretry.yml new file mode 100644 index 00000000000..3b555758951 --- /dev/null +++ b/changelogs/fragments/951-cloudretry.yml @@ -0,0 +1,2 @@ +deprecated_features: +- module_utils.cloud - removal of the ``CloudRetry.backoff`` has been delayed until release 6.0.0. It is recommended to update custom modules to use ``jittered_backoff`` or ``exponential_backoff`` instead (https://github.com/ansible-collections/amazon.aws/pull/951). diff --git a/plugins/module_utils/cloud.py b/plugins/module_utils/cloud.py index 600a7ed158b..ba2fac74c4d 100644 --- a/plugins/module_utils/cloud.py +++ b/plugins/module_utils/cloud.py @@ -32,6 +32,7 @@ import time import functools import random +import ansible.module_utils.common.warnings as ansible_warnings class BackoffIterator: @@ -100,7 +101,7 @@ def status_code_from_exception(error): def found(response_code, catch_extra_error_codes=None): def _is_iterable(): try: - it = iter(catch_extra_error_codes) + iter(catch_extra_error_codes) except TypeError: # not iterable return False @@ -184,7 +185,7 @@ def backoff(cls, tries=10, delay=3, backoff=1.1, catch_extra_error_codes=None): """ Wrap a callable with retry behavior. Developers should use CloudRetry.exponential_backoff instead. - This method has been deprecated and will be removed in release 4.0.0, consider using exponential_backoff method instead. + This method has been deprecated and will be removed in release 6.0.0, consider using exponential_backoff method instead. Args: retries (int): Number of times to retry a failed request before giving up default=10 @@ -197,6 +198,12 @@ def backoff(cls, tries=10, delay=3, backoff=1.1, catch_extra_error_codes=None): Returns: Callable: A generator that calls the decorated function using an exponential backoff. """ + # This won't emit a warning (we don't have the context available to us), but will trigger + # sanity failures as we prepare for 6.0.0 + ansible_warnings.deprecate( + 'CloudRetry.backoff has been deprecated, please use CloudRetry.exponential_backoff instead', + version='6.0.0', collection_name='amazon.aws') + return cls.exponential_backoff( retries=tries, delay=delay, diff --git a/tests/unit/module_utils/test_cloud.py b/tests/unit/module_utils/test_cloud.py index f54dc2dc66e..1486da01f5f 100644 --- a/tests/unit/module_utils/test_cloud.py +++ b/tests/unit/module_utils/test_cloud.py @@ -113,6 +113,23 @@ def setUp(self): # nothing to do on setup stage pass + # ======================================================== + # retry original backoff + # ======================================================== + def test_retry_backoff(self): + + @CloudRetryUtils.UnitTestsRetry.backoff(tries=3, delay=1, backoff=1.1, catch_extra_error_codes=CloudRetryUtils.error_codes) + def test_retry_func(): + if test_retry_func.counter < 2: + test_retry_func.counter += 1 + raise self.TestException(status=random.choice(CloudRetryUtils.error_codes)) + else: + return True + + test_retry_func.counter = 0 + ret = test_retry_func() + assert ret is True + # ======================================================== # retry exponential backoff # ======================================================== @@ -142,10 +159,10 @@ def test_retry_func(): raise unexpected_except test_retry_func.counter = 0 - try: - ret = test_retry_func() - except self.TestException as exc: - assert exc.status == unexpected_except.status + with self.assertRaises(self.TestException) as exc: + test_retry_func() + + assert exc.exception.status == unexpected_except.status # ======================================================== # retry jittered backoff @@ -175,10 +192,10 @@ def test_retry_func(): raise unexpected_except test_retry_func.counter = 0 - try: - ret = test_retry_func() - except self.TestException as exc: - assert exc.status == unexpected_except.status + with self.assertRaises(self.TestException) as exc: + test_retry_func() + + assert exc.exception.status == unexpected_except.status # ======================================================== # retry with custom class @@ -210,17 +227,13 @@ def _fail(): # run the method 3 times and assert that each it is retrying after 2secs # the elapsed execution time should be closed to 2sec - for u in range(3): + for _i in range(3): start = datetime.now() raised = False - try: + with self.assertRaises(self.TestException): _fail() - except self.TestException: - raised = True - duration = (datetime.now() - start).seconds - assert duration == 2 - finally: - assert raised + duration = (datetime.now() - start).seconds + assert duration == 2 def test_only_base_exception(self): def _fail_index(): @@ -253,11 +266,7 @@ def _fail_exception(): start = datetime.now() raised = False - try: + with self.assertRaises(Exception): decorator(function)() - except Exception: - raised = True - _duration = (datetime.now() - start).seconds - assert duration == _duration - finally: - assert raised + _duration = (datetime.now() - start).seconds + assert duration == _duration