blob: 7c30f9d8280145d0272c04dd6ebe907d684fd8a1 [file] [log] [blame]
Max Rasskazovc018e382015-06-03 15:22:04 +03001#-*- coding: utf-8 -*-
2
3
4import logging
5import os
6import time
7
8
9logging.basicConfig()
10logger = logging.getLogger('safe_rsync')
11
12loglevel = os.environ.get('LOGLEVEL', 'INFO')
13if loglevel not in ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'):
14 logger.warn('LOGLEVEL environment variable has wrong value=={}. Using '
15 '"INFO" by default.'.format(loglevel))
16 loglevel = 'INFO'
17logger.setLevel(loglevel)
18
19
20def logged(logger=None):
21 if logger is None:
22 logger = globals().get('logger')
23
24 def wrap(f):
25 def wrapped_f(*args, **kwargs):
26 logger.debug('Starting {}({}, {}) (defaults: {})'
27 ''.format(f.__name__,
28 str(args),
29 str(kwargs),
30 str(f.__defaults__))
31 )
32 r = f(*args, **kwargs)
33 logger.debug('{} done with result "{}".'.
34 format(f.__name__, str(r)))
35 return r
36 return wrapped_f
37 return wrap
38
39
Max Rasskazovc018e382015-06-03 15:22:04 +030040class ResultNotProduced(Exception):
41 def __init__(self, value):
42 self.value = value
43
44 def __str__(self):
45 return repr(self.value)
46
47
48class Retry(object):
49 """
50 Waits while the function reaches the specified status.
51
52 :param function: function that returns some status
53 :param expected_status: status the machine should turn to
54 :param attempts: how many times to check status
55 :param timeout: timeout in seconds before attempts
56 :return: True if node moves to the specified status, False otherwise
57 :Examples:
58 Retry(timeout=3, attempts=10).wait(function, result, param1, param2)
59 Retry().wait_result(function, result, param1, param2)
60 """
61
62 def __init__(self, timeout=5, attempts=10):
63 self.timeout = timeout
64 self.attempts = attempts
65 self.logger = globals().get('logger').getChild('Retry')
66
67 def wait_result(self, function, expected_result, *args, **kwargs):
68
69 self.logger.debug('Wait for {}() == {}...'
70 ''.format(function.__name__, str(expected_result)))
71
72 @logged(self.logger)
73 def f():
74 return function(*args, **kwargs)
75
76 attempt = 1
77 while attempt <= self.attempts:
78 try:
79 result = f()
80 except Exception as e:
81 self.logger.error('Exception on function {}: {}'
82 ''.format(function.__name__, str(e)))
83 raise
84 else:
85 if result == expected_result:
86 self.logger.debug('Got on attempt #{}:'.format(attempt))
87 return result
88 attempt += 1
89 time.sleep(self.timeout)
90
91 raise ResultNotProduced('Result "{}" was not produced during '
92 '{} attempts.'
93 ''.format(expected_result, attempt - 1))