summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml3
-rw-r--r--ChangeLog2
-rw-r--r--README.md2
-rw-r--r--fail2ban/server/actions.py5
-rw-r--r--fail2ban/server/server.py4
-rw-r--r--fail2ban/server/utils.py30
-rw-r--r--fail2ban/tests/actiontestcase.py108
-rw-r--r--fail2ban/tests/misctestcase.py16
-rw-r--r--fail2ban/tests/observertestcase.py2
-rw-r--r--fail2ban/tests/servertestcase.py26
10 files changed, 78 insertions, 120 deletions
diff --git a/.travis.yml b/.travis.yml
index 398c120a..502af5be 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -33,7 +33,8 @@ install:
# coverage
- travis_retry pip install coverage
# coveralls (note coveralls doesn't support 2.6 now):
- - if [[ $TRAVIS_PYTHON_VERSION != 2.6* ]]; then F2B_COV=1; else F2B_COV=0; fi
+ #- if [[ $TRAVIS_PYTHON_VERSION != 2.6* ]]; then F2B_COV=1; else F2B_COV=0; fi
+ - F2B_COV=1
- if [[ "$F2B_COV" = 1 ]]; then travis_retry pip install coveralls; fi
# codecov:
- travis_retry pip install codecov
diff --git a/ChangeLog b/ChangeLog
index a022f17c..d294ad54 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,6 +10,8 @@ ver. 1.0.1-dev-1 (20??/??/??) - development nightly edition
-----------
### Compatibility:
+* the minimum supported python version is now 2.7, if you have previous python version
+ you can use the 0.11 version of fail2ban or upgrade python (or even build it from source).
* potential incompatibility by parsing of options of `backend`, `filter` and `action` parameters (if they
are partially incorrect), because fail2ban could throw an error now (doesn't silently bypass it anymore).
* to v.0.11:
diff --git a/README.md b/README.md
index ba5c149e..6bf94c25 100644
--- a/README.md
+++ b/README.md
@@ -33,7 +33,7 @@ Installation:
this case, you should use that instead.**
Required:
-- [Python2 >= 2.6 or Python >= 3.2](https://www.python.org) or [PyPy](https://pypy.org)
+- [Python2 >= 2.7 or Python >= 3.2](https://www.python.org) or [PyPy](https://pypy.org)
- python-setuptools, python-distutils or python3-setuptools for installation from source
Optional:
diff --git a/fail2ban/server/actions.py b/fail2ban/server/actions.py
index 54e0c02a..0cd2ec33 100644
--- a/fail2ban/server/actions.py
+++ b/fail2ban/server/actions.py
@@ -32,10 +32,7 @@ try:
from collections.abc import Mapping
except ImportError:
from collections import Mapping
-try:
- from collections import OrderedDict
-except ImportError:
- OrderedDict = dict
+from collections import OrderedDict
from .banmanager import BanManager, BanTicket
from .ipdns import IPAddr
diff --git a/fail2ban/server/server.py b/fail2ban/server/server.py
index 3853bbc4..36ed1b0d 100644
--- a/fail2ban/server/server.py
+++ b/fail2ban/server/server.py
@@ -728,9 +728,7 @@ class Server:
except (ValueError, KeyError): # pragma: no cover
# Is known to be thrown after logging was shutdown once
# with older Pythons -- seems to be safe to ignore there
- # At least it was still failing on 2.6.2-0ubuntu1 (jaunty)
- if (2, 6, 3) <= sys.version_info < (3,) or \
- (3, 2) <= sys.version_info:
+ if sys.version_info < (3,) or sys.version_info >= (3, 2):
raise
# detailed format by deep log levels (as DEBUG=10):
if logger.getEffectiveLevel() <= logging.DEBUG: # pragma: no cover
diff --git a/fail2ban/server/utils.py b/fail2ban/server/utils.py
index 8483b013..18073ea7 100644
--- a/fail2ban/server/utils.py
+++ b/fail2ban/server/utils.py
@@ -30,11 +30,7 @@ import sys
from threading import Lock
import time
from ..helpers import getLogger, _merge_dicts, uni_decode
-
-try:
- from collections import OrderedDict
-except ImportError: # pragma: 3.x no cover
- OrderedDict = dict
+from collections import OrderedDict
if sys.version_info >= (3, 3):
import importlib.machinery
@@ -100,24 +96,12 @@ class Utils():
with self.__lock:
# clean cache if max count reached:
if len(cache) >= self.maxCount:
- if OrderedDict is not dict:
- # ordered (so remove some from ahead, FIFO)
- while cache:
- (ck, cv) = cache.popitem(last=False)
- # if not yet expired (but has free slot for new entry):
- if cv[1] > t and len(cache) < self.maxCount:
- break
- else: # pragma: 3.x no cover (dict is in 2.6 only)
- remlst = []
- for (ck, cv) in cache.iteritems():
- # if expired:
- if cv[1] <= t:
- remlst.append(ck)
- for ck in remlst:
- self._cache.pop(ck, None)
- # if still max count - remove any one:
- while cache and len(cache) >= self.maxCount:
- cache.popitem()
+ # ordered (so remove some from ahead, FIFO)
+ while cache:
+ (ck, cv) = cache.popitem(last=False)
+ # if not yet expired (but has free slot for new entry):
+ if cv[1] > t and len(cache) < self.maxCount:
+ break
# set now:
cache[k] = (v, t + self.maxTime)
diff --git a/fail2ban/tests/actiontestcase.py b/fail2ban/tests/actiontestcase.py
index 64476f56..ce5de483 100644
--- a/fail2ban/tests/actiontestcase.py
+++ b/fail2ban/tests/actiontestcase.py
@@ -75,61 +75,59 @@ class CommandActionTest(LogCaptureTestCase):
lambda: substituteRecursiveTags({'A': 'to=<B> fromip=<IP>', 'C': '<B>', 'B': '<C>', 'D': ''}))
self.assertRaises(ValueError,
lambda: substituteRecursiveTags({'failregex': 'to=<honeypot> fromip=<IP>', 'sweet': '<honeypot>', 'honeypot': '<sweet>', 'ignoreregex': ''}))
- # We need here an ordered, because the sequence of iteration is very important for this test
- if OrderedDict:
- # No cyclic recursion, just multiple replacement of tag <T>, should be successful:
- self.assertEqual(substituteRecursiveTags( OrderedDict(
- (('X', 'x=x<T>'), ('T', '1'), ('Z', '<X> <T> <Y>'), ('Y', 'y=y<T>')))
- ), {'X': 'x=x1', 'T': '1', 'Y': 'y=y1', 'Z': 'x=x1 1 y=y1'}
- )
- # No cyclic recursion, just multiple replacement of tag <T> in composite tags, should be successful:
- self.assertEqual(substituteRecursiveTags( OrderedDict(
- (('X', 'x=x<T> <Z> <<R1>> <<R2>>'), ('R1', 'Z'), ('R2', 'Y'), ('T', '1'), ('Z', '<T> <Y>'), ('Y', 'y=y<T>')))
- ), {'X': 'x=x1 1 y=y1 1 y=y1 y=y1', 'R1': 'Z', 'R2': 'Y', 'T': '1', 'Z': '1 y=y1', 'Y': 'y=y1'}
- )
- # No cyclic recursion, just multiple replacement of same tags, should be successful:
- self.assertEqual(substituteRecursiveTags( OrderedDict((
- ('actionstart', 'ipset create <ipmset> hash:ip timeout <bantime> family <ipsetfamily>\n<iptables> -I <chain> <actiontype>'),
- ('ipmset', 'f2b-<name>'),
- ('name', 'any'),
- ('bantime', '600'),
- ('ipsetfamily', 'inet'),
- ('iptables', 'iptables <lockingopt>'),
- ('lockingopt', '-w'),
- ('chain', 'INPUT'),
- ('actiontype', '<multiport>'),
- ('multiport', '-p <protocol> -m multiport --dports <port> -m set --match-set <ipmset> src -j <blocktype>'),
- ('protocol', 'tcp'),
- ('port', 'ssh'),
- ('blocktype', 'REJECT',),
- ))
- ), OrderedDict((
- ('actionstart', 'ipset create f2b-any hash:ip timeout 600 family inet\niptables -w -I INPUT -p tcp -m multiport --dports ssh -m set --match-set f2b-any src -j REJECT'),
- ('ipmset', 'f2b-any'),
- ('name', 'any'),
- ('bantime', '600'),
- ('ipsetfamily', 'inet'),
- ('iptables', 'iptables -w'),
- ('lockingopt', '-w'),
- ('chain', 'INPUT'),
- ('actiontype', '-p tcp -m multiport --dports ssh -m set --match-set f2b-any src -j REJECT'),
- ('multiport', '-p tcp -m multiport --dports ssh -m set --match-set f2b-any src -j REJECT'),
- ('protocol', 'tcp'),
- ('port', 'ssh'),
- ('blocktype', 'REJECT')
- ))
- )
- # Cyclic recursion by composite tag creation, tags "create" another tag, that closes cycle:
- self.assertRaises(ValueError, lambda: substituteRecursiveTags( OrderedDict((
- ('A', '<<B><C>>'),
- ('B', 'D'), ('C', 'E'),
- ('DE', 'cycle <A>'),
- )) ))
- self.assertRaises(ValueError, lambda: substituteRecursiveTags( OrderedDict((
- ('DE', 'cycle <A>'),
- ('A', '<<B><C>>'),
- ('B', 'D'), ('C', 'E'),
- )) ))
+ # No cyclic recursion, just multiple replacement of tag <T>, should be successful:
+ self.assertEqual(substituteRecursiveTags( OrderedDict(
+ (('X', 'x=x<T>'), ('T', '1'), ('Z', '<X> <T> <Y>'), ('Y', 'y=y<T>')))
+ ), {'X': 'x=x1', 'T': '1', 'Y': 'y=y1', 'Z': 'x=x1 1 y=y1'}
+ )
+ # No cyclic recursion, just multiple replacement of tag <T> in composite tags, should be successful:
+ self.assertEqual(substituteRecursiveTags( OrderedDict(
+ (('X', 'x=x<T> <Z> <<R1>> <<R2>>'), ('R1', 'Z'), ('R2', 'Y'), ('T', '1'), ('Z', '<T> <Y>'), ('Y', 'y=y<T>')))
+ ), {'X': 'x=x1 1 y=y1 1 y=y1 y=y1', 'R1': 'Z', 'R2': 'Y', 'T': '1', 'Z': '1 y=y1', 'Y': 'y=y1'}
+ )
+ # No cyclic recursion, just multiple replacement of same tags, should be successful:
+ self.assertEqual(substituteRecursiveTags( OrderedDict((
+ ('actionstart', 'ipset create <ipmset> hash:ip timeout <bantime> family <ipsetfamily>\n<iptables> -I <chain> <actiontype>'),
+ ('ipmset', 'f2b-<name>'),
+ ('name', 'any'),
+ ('bantime', '600'),
+ ('ipsetfamily', 'inet'),
+ ('iptables', 'iptables <lockingopt>'),
+ ('lockingopt', '-w'),
+ ('chain', 'INPUT'),
+ ('actiontype', '<multiport>'),
+ ('multiport', '-p <protocol> -m multiport --dports <port> -m set --match-set <ipmset> src -j <blocktype>'),
+ ('protocol', 'tcp'),
+ ('port', 'ssh'),
+ ('blocktype', 'REJECT',),
+ ))
+ ), OrderedDict((
+ ('actionstart', 'ipset create f2b-any hash:ip timeout 600 family inet\niptables -w -I INPUT -p tcp -m multiport --dports ssh -m set --match-set f2b-any src -j REJECT'),
+ ('ipmset', 'f2b-any'),
+ ('name', 'any'),
+ ('bantime', '600'),
+ ('ipsetfamily', 'inet'),
+ ('iptables', 'iptables -w'),
+ ('lockingopt', '-w'),
+ ('chain', 'INPUT'),
+ ('actiontype', '-p tcp -m multiport --dports ssh -m set --match-set f2b-any src -j REJECT'),
+ ('multiport', '-p tcp -m multiport --dports ssh -m set --match-set f2b-any src -j REJECT'),
+ ('protocol', 'tcp'),
+ ('port', 'ssh'),
+ ('blocktype', 'REJECT')
+ ))
+ )
+ # Cyclic recursion by composite tag creation, tags "create" another tag, that closes cycle:
+ self.assertRaises(ValueError, lambda: substituteRecursiveTags( OrderedDict((
+ ('A', '<<B><C>>'),
+ ('B', 'D'), ('C', 'E'),
+ ('DE', 'cycle <A>'),
+ )) ))
+ self.assertRaises(ValueError, lambda: substituteRecursiveTags( OrderedDict((
+ ('DE', 'cycle <A>'),
+ ('A', '<<B><C>>'),
+ ('B', 'D'), ('C', 'E'),
+ )) ))
# missing tags are ok
self.assertEqual(substituteRecursiveTags({'A': '<C>'}), {'A': '<C>'})
diff --git a/fail2ban/tests/misctestcase.py b/fail2ban/tests/misctestcase.py
index e2faa6fd..4b026377 100644
--- a/fail2ban/tests/misctestcase.py
+++ b/fail2ban/tests/misctestcase.py
@@ -70,16 +70,10 @@ class HelpersTest(unittest.TestCase):
self.assertEqual(splitwords(u' 1\n 2, 3'), ['1', '2', '3'])
-if sys.version_info >= (2,7):
- def _sh_call(cmd):
- import subprocess
- ret = subprocess.check_output(cmd, shell=True)
- return uni_decode(ret).rstrip()
-else:
- def _sh_call(cmd):
- import subprocess
- ret = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout.read()
- return uni_decode(ret).rstrip()
+def _sh_call(cmd):
+ import subprocess
+ ret = subprocess.check_output(cmd, shell=True)
+ return uni_decode(ret).rstrip()
def _getSysPythonVersion():
return _sh_call("fail2ban-python -c 'import sys; print(tuple(sys.version_info))'")
@@ -92,7 +86,7 @@ class SetupTest(unittest.TestCase):
unittest.F2B.SkipIfFast()
setup = os.path.join(os.path.dirname(__file__), '..', '..', 'setup.py')
self.setup = os.path.exists(setup) and setup or None
- if not self.setup and sys.version_info >= (2,7): # pragma: no cover - running not out of the source
+ if not self.setup: # pragma: no cover - running not out of the source
raise unittest.SkipTest(
"Seems to be running not out of source distribution"
" -- cannot locate setup.py")
diff --git a/fail2ban/tests/observertestcase.py b/fail2ban/tests/observertestcase.py
index 38cfc881..315c955a 100644
--- a/fail2ban/tests/observertestcase.py
+++ b/fail2ban/tests/observertestcase.py
@@ -181,7 +181,7 @@ class BanTimeIncrDB(LogCaptureTestCase):
def setUp(self):
"""Call before every test case."""
super(BanTimeIncrDB, self).setUp()
- if Fail2BanDb is None and sys.version_info >= (2,7): # pragma: no cover
+ if Fail2BanDb is None: # pragma: no cover
raise unittest.SkipTest(
"Unable to import fail2ban database module as sqlite is not "
"available.")
diff --git a/fail2ban/tests/servertestcase.py b/fail2ban/tests/servertestcase.py
index b7ad4d32..62ae81fd 100644
--- a/fail2ban/tests/servertestcase.py
+++ b/fail2ban/tests/servertestcase.py
@@ -775,27 +775,11 @@ class Transmitter(TransmitterBase):
def testPythonActionMethodsAndProperties(self):
action = "TestCaseAction"
- try:
- out = self.transm.proceed(
- ["set", self.jailName, "addaction", action,
- os.path.join(TEST_FILES_DIR, "action.d", "action.py"),
- '{"opt1": "value"}'])
- self.assertEqual(out, (0, action))
- except AssertionError:
- if ((2, 6) <= sys.version_info < (2, 6, 5)) \
- and '__init__() keywords must be strings' in out[1]:
- # known issue http://bugs.python.org/issue2646 in 2.6 series
- # since general Fail2Ban warnings are suppressed in normal
- # operation -- let's issue Python's native warning here
- import warnings
- warnings.warn(
- "Your version of Python %s seems to experience a known "
- "issue forbidding correct operation of Fail2Ban: "
- "http://bugs.python.org/issue2646 Upgrade your Python and "
- "meanwhile other intestPythonActionMethodsAndProperties will "
- "be skipped" % (sys.version))
- return
- raise
+ out = self.transm.proceed(
+ ["set", self.jailName, "addaction", action,
+ os.path.join(TEST_FILES_DIR, "action.d", "action.py"),
+ '{"opt1": "value"}'])
+ self.assertEqual(out, (0, action))
self.assertSortedEqual(
self.transm.proceed(["get", self.jailName,
"actionproperties", action])[1],