diff --git a/lib/utils.py b/lib/utils.py index 2864b00243a98be4ec590aade01a68503c3c3931..ce112c91443ab38e99f6b8dfe67fcdec9922c155 100644 --- a/lib/utils.py +++ b/lib/utils.py @@ -2499,6 +2499,11 @@ class RetryTimeout(Exception): """Retry loop timed out. """ + def RaiseInner(self): + if self.args and isinstance(self.args[0], Exception): + raise self.args[0] + else: + raise RetryTimeout(*self.args) class RetryAgain(Exception): @@ -2612,11 +2617,12 @@ def Retry(fn, delay, timeout, args=None, wait_fn=time.sleep, assert calc_delay is None or callable(calc_delay) while True: + retry_args = [] try: # pylint: disable-msg=W0142 return fn(*args) - except RetryAgain: - pass + except RetryAgain, err: + retry_args = err.args except RetryTimeout: raise errors.ProgrammerError("Nested retry loop detected that didn't" " handle RetryTimeout") @@ -2624,7 +2630,8 @@ def Retry(fn, delay, timeout, args=None, wait_fn=time.sleep, remaining_time = end_time - _time_fn() if remaining_time < 0.0: - raise RetryTimeout() + # pylint: disable-msg=W0142 + raise RetryTimeout(*retry_args) assert remaining_time >= 0.0 diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py index bad5a9a4340d09c2390d64b88ebb32e1cbe97309..55698f59afd4a1b5552951a0cdca99c747254d3d 100755 --- a/test/ganeti.utils_unittest.py +++ b/test/ganeti.utils_unittest.py @@ -1612,6 +1612,10 @@ class TestRetry(testutils.GanetiTestCase): def _RaiseRetryAgain(): raise utils.RetryAgain() + @staticmethod + def _RaiseRetryAgainWithArg(args): + raise utils.RetryAgain(*args) + def _WrongNestedLoop(self): return utils.Retry(self._RaiseRetryAgain, 0.01, 0.02) @@ -1642,6 +1646,45 @@ class TestRetry(testutils.GanetiTestCase): except utils.RetryTimeout: self.fail("Didn't detect inner loop's exception") + def testTimeoutArgument(self): + retry_arg="my_important_debugging_message" + try: + utils.Retry(self._RaiseRetryAgainWithArg, 0.01, 0.02, args=[[retry_arg]]) + except utils.RetryTimeout, err: + self.failUnlessEqual(err.args, (retry_arg, )) + else: + self.fail("Expected timeout didn't happen") + + def testRaiseInnerWithExc(self): + retry_arg="my_important_debugging_message" + try: + try: + utils.Retry(self._RaiseRetryAgainWithArg, 0.01, 0.02, + args=[[errors.GenericError(retry_arg, retry_arg)]]) + except utils.RetryTimeout, err: + err.RaiseInner() + else: + self.fail("Expected timeout didn't happen") + except errors.GenericError, err: + self.failUnlessEqual(err.args, (retry_arg, retry_arg)) + else: + self.fail("Expected GenericError didn't happen") + + def testRaiseInnerWithMsg(self): + retry_arg="my_important_debugging_message" + try: + try: + utils.Retry(self._RaiseRetryAgainWithArg, 0.01, 0.02, + args=[[retry_arg, retry_arg]]) + except utils.RetryTimeout, err: + err.RaiseInner() + else: + self.fail("Expected timeout didn't happen") + except utils.RetryTimeout, err: + self.failUnlessEqual(err.args, (retry_arg, retry_arg)) + else: + self.fail("Expected RetryTimeout didn't happen") + class TestLineSplitter(unittest.TestCase): def test(self):