mirror of https://github.com/fail2ban/fail2ban
increase performance of executeCmd (actions), thereby introduced new shorter interval for fast operations (leaves unchanged default wait operation intervals (sleep time, threshold interval) - for the same inertance, to save same system (load by many jails resp. log files);
extends wait_for with callable timeout (test case fixed);pull/1562/head
parent
5151c4fa6d
commit
b011cf17b2
|
@ -54,6 +54,7 @@ class Utils():
|
||||||
|
|
||||||
DEFAULT_SLEEP_TIME = 2
|
DEFAULT_SLEEP_TIME = 2
|
||||||
DEFAULT_SLEEP_INTERVAL = 0.2
|
DEFAULT_SLEEP_INTERVAL = 0.2
|
||||||
|
DEFAULT_SHORT_INTERVAL = 0.001
|
||||||
|
|
||||||
|
|
||||||
class Cache(object):
|
class Cache(object):
|
||||||
|
@ -134,21 +135,22 @@ class Utils():
|
||||||
"""
|
"""
|
||||||
stdout = stderr = None
|
stdout = stderr = None
|
||||||
retcode = None
|
retcode = None
|
||||||
if not callable(timeout):
|
|
||||||
stime = time.time()
|
|
||||||
timeout_expr = lambda: time.time() - stime <= timeout
|
|
||||||
else:
|
|
||||||
timeout_expr = timeout
|
|
||||||
popen = None
|
popen = None
|
||||||
try:
|
try:
|
||||||
popen = subprocess.Popen(
|
popen = subprocess.Popen(
|
||||||
realCmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=shell,
|
realCmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=shell,
|
||||||
preexec_fn=os.setsid # so that killpg does not kill our process
|
preexec_fn=os.setsid # so that killpg does not kill our process
|
||||||
)
|
)
|
||||||
|
# wait with timeout for process has terminated:
|
||||||
retcode = popen.poll()
|
retcode = popen.poll()
|
||||||
while retcode is None and timeout_expr():
|
if retcode is None:
|
||||||
time.sleep(Utils.DEFAULT_SLEEP_INTERVAL)
|
def _popen_wait_end():
|
||||||
retcode = popen.poll()
|
retcode = popen.poll()
|
||||||
|
return (True, retcode) if retcode is not None else None
|
||||||
|
retcode = Utils.wait_for(_popen_wait_end, timeout, Utils.DEFAULT_SHORT_INTERVAL)
|
||||||
|
if retcode:
|
||||||
|
retcode = retcode[1]
|
||||||
|
# if timeout:
|
||||||
if retcode is None:
|
if retcode is None:
|
||||||
logSys.error("%s -- timed out after %s seconds." %
|
logSys.error("%s -- timed out after %s seconds." %
|
||||||
(realCmd, timeout))
|
(realCmd, timeout))
|
||||||
|
@ -202,18 +204,18 @@ class Utils():
|
||||||
|
|
||||||
success = False
|
success = False
|
||||||
if retcode == 0:
|
if retcode == 0:
|
||||||
logSys.debug("%s -- returned successfully", realCmd)
|
logSys.debug("%-.40s -- returned successfully", realCmd)
|
||||||
success = True
|
success = True
|
||||||
elif retcode is None:
|
elif retcode is None:
|
||||||
logSys.error("%s -- unable to kill PID %i" % (realCmd, popen.pid))
|
logSys.error("%-.40s -- unable to kill PID %i", realCmd, popen.pid)
|
||||||
elif retcode < 0 or retcode > 128:
|
elif retcode < 0 or retcode > 128:
|
||||||
# dash would return negative while bash 128 + n
|
# dash would return negative while bash 128 + n
|
||||||
sigcode = -retcode if retcode < 0 else retcode - 128
|
sigcode = -retcode if retcode < 0 else retcode - 128
|
||||||
logSys.error("%s -- killed with %s (return code: %s)" %
|
logSys.error("%-.40s -- killed with %s (return code: %s)",
|
||||||
(realCmd, signame.get(sigcode, "signal %i" % sigcode), retcode))
|
realCmd, signame.get(sigcode, "signal %i" % sigcode), retcode)
|
||||||
else:
|
else:
|
||||||
msg = _RETCODE_HINTS.get(retcode, None)
|
msg = _RETCODE_HINTS.get(retcode, None)
|
||||||
logSys.error("%s -- returned %i" % (realCmd, retcode))
|
logSys.error("%-.40s -- returned %i", realCmd, retcode)
|
||||||
if msg:
|
if msg:
|
||||||
logSys.info("HINT on %i: %s", retcode, msg % locals())
|
logSys.info("HINT on %i: %s", retcode, msg % locals())
|
||||||
return success if not output else (success, stdout, stderr, retcode)
|
return success if not output else (success, stdout, stderr, retcode)
|
||||||
|
@ -221,7 +223,25 @@ class Utils():
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def wait_for(cond, timeout, interval=None):
|
def wait_for(cond, timeout, interval=None):
|
||||||
"""Wait until condition expression `cond` is True, up to `timeout` sec
|
"""Wait until condition expression `cond` is True, up to `timeout` sec
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
cond : callable
|
||||||
|
The expression to check condition
|
||||||
|
(should return equivalent to bool True if wait successful).
|
||||||
|
timeout : float or callable
|
||||||
|
The time out for end of wait
|
||||||
|
(in seconds or callable that returns True if timeout occurred).
|
||||||
|
interval : float (optional)
|
||||||
|
Polling start interval for wait cycle in seconds.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
variable
|
||||||
|
The return value of the last call of `cond`,
|
||||||
|
logical False (or None, 0, etc) if timeout occurred.
|
||||||
"""
|
"""
|
||||||
|
#logSys.log(5, " wait for %r, tout: %r / %r", cond, timeout, interval)
|
||||||
ini = 1 # to delay initializations until/when necessary
|
ini = 1 # to delay initializations until/when necessary
|
||||||
while True:
|
while True:
|
||||||
ret = cond()
|
ret = cond()
|
||||||
|
@ -229,10 +249,14 @@ class Utils():
|
||||||
return ret
|
return ret
|
||||||
if ini:
|
if ini:
|
||||||
ini = stm = 0
|
ini = stm = 0
|
||||||
time0 = time.time() + timeout
|
if not callable(timeout):
|
||||||
|
time0 = time.time() + timeout
|
||||||
|
timeout_expr = lambda: time.time() > time0
|
||||||
|
else:
|
||||||
|
timeout_expr = timeout
|
||||||
if not interval:
|
if not interval:
|
||||||
interval = Utils.DEFAULT_SLEEP_INTERVAL
|
interval = Utils.DEFAULT_SLEEP_INTERVAL
|
||||||
if time.time() > time0:
|
if timeout_expr():
|
||||||
break
|
break
|
||||||
stm = min(stm + interval, Utils.DEFAULT_SLEEP_TIME)
|
stm = min(stm + interval, Utils.DEFAULT_SLEEP_TIME)
|
||||||
time.sleep(stm)
|
time.sleep(stm)
|
||||||
|
|
|
@ -353,8 +353,8 @@ class CommandActionTest(LogCaptureTestCase):
|
||||||
# timeout as long as pid-file was not created, but max 5 seconds
|
# timeout as long as pid-file was not created, but max 5 seconds
|
||||||
def getnasty_tout():
|
def getnasty_tout():
|
||||||
return (
|
return (
|
||||||
getnastypid() is None
|
getnastypid() is not None
|
||||||
and time.time() - stime <= 5
|
or time.time() - stime > 5
|
||||||
)
|
)
|
||||||
|
|
||||||
def getnastypid():
|
def getnastypid():
|
||||||
|
|
|
@ -239,6 +239,7 @@ def initTests(opts):
|
||||||
# (prevent long sleeping during test cases ... less time goes to sleep):
|
# (prevent long sleeping during test cases ... less time goes to sleep):
|
||||||
Utils.DEFAULT_SLEEP_TIME = 0.0025
|
Utils.DEFAULT_SLEEP_TIME = 0.0025
|
||||||
Utils.DEFAULT_SLEEP_INTERVAL = 0.0005
|
Utils.DEFAULT_SLEEP_INTERVAL = 0.0005
|
||||||
|
Utils.DEFAULT_SHORT_INTERVAL = 0.0001
|
||||||
def F2B_SkipIfFast():
|
def F2B_SkipIfFast():
|
||||||
raise unittest.SkipTest('Skip test because of "--fast"')
|
raise unittest.SkipTest('Skip test because of "--fast"')
|
||||||
unittest.F2B.SkipIfFast = F2B_SkipIfFast
|
unittest.F2B.SkipIfFast = F2B_SkipIfFast
|
||||||
|
@ -246,6 +247,7 @@ def initTests(opts):
|
||||||
# smaller inertance inside test-cases (litle speedup):
|
# smaller inertance inside test-cases (litle speedup):
|
||||||
Utils.DEFAULT_SLEEP_TIME = 0.25
|
Utils.DEFAULT_SLEEP_TIME = 0.25
|
||||||
Utils.DEFAULT_SLEEP_INTERVAL = 0.025
|
Utils.DEFAULT_SLEEP_INTERVAL = 0.025
|
||||||
|
Utils.DEFAULT_SHORT_INTERVAL = 0.0005
|
||||||
# sleep intervals are large - use replacement for sleep to check time to sleep:
|
# sleep intervals are large - use replacement for sleep to check time to sleep:
|
||||||
_org_sleep = time.sleep
|
_org_sleep = time.sleep
|
||||||
def _new_sleep(v):
|
def _new_sleep(v):
|
||||||
|
|
Loading…
Reference in New Issue