diff --git a/bin/fail2ban-testcases b/bin/fail2ban-testcases index 98b9118f..dcc55421 100755 --- a/bin/fail2ban-testcases +++ b/bin/fail2ban-testcases @@ -38,11 +38,14 @@ if os.path.exists("fail2ban/__init__.py"): from fail2ban.version import version from fail2ban.tests.utils import gatherTests -from fail2ban.helpers import FormatterWithTraceBack, getLogger +from fail2ban.helpers import updatePyExec, FormatterWithTraceBack, getLogger from fail2ban.server.mytime import MyTime from optparse import OptionParser, Option +# Update fail2ban-python env to current python version (where f2b-modules located/installed) +updatePyExec(os.path.dirname(__file__)) + def get_opt_parser(): # use module docstring for help output p = OptionParser( diff --git a/config/filter.d/ignorecommands/apache-fakegooglebot b/config/filter.d/ignorecommands/apache-fakegooglebot index fe4b6591..68a2cb5b 100755 --- a/config/filter.d/ignorecommands/apache-fakegooglebot +++ b/config/filter.d/ignorecommands/apache-fakegooglebot @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env fail2ban-python # Inspired by https://isc.sans.edu/forums/diary/When+Google+isnt+Google/15968/ # # Written in Python to reuse built-in Python batteries and not depend on diff --git a/fail2ban/helpers.py b/fail2ban/helpers.py index 7660e64a..99210b17 100644 --- a/fail2ban/helpers.py +++ b/fail2ban/helpers.py @@ -118,6 +118,24 @@ class FormatterWithTraceBack(logging.Formatter): return logging.Formatter.format(self, record) +def updatePyExec(bindir, executable=None): + """Update fail2ban-python link to current python version (where f2b-modules located/installed) + """ + bindir = os.path.realpath(bindir) + if executable is None: + executable = sys.executable + pypath = os.path.join(bindir, 'fail2ban-python') + # if not exists or point to another version - update link: + isfile = os.path.isfile(pypath) + if not isfile or os.path.realpath(pypath) != os.path.realpath(executable): + if isfile: + os.unlink(pypath) + os.symlink(executable, pypath) + # extend current environment path (e.g. if fail2ban not yet installed): + if bindir not in os.environ["PATH"].split(os.pathsep): + os.environ["PATH"] = os.environ["PATH"] + os.pathsep + bindir; + + def getLogger(name): """Get logging.Logger instance with Fail2Ban logger name convention """ diff --git a/fail2ban/tests/files/config/apache-auth/digest.py b/fail2ban/tests/files/config/apache-auth/digest.py index f4fcfcb9..03588594 100755 --- a/fail2ban/tests/files/config/apache-auth/digest.py +++ b/fail2ban/tests/files/config/apache-auth/digest.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env fail2ban-python import requests try: diff --git a/fail2ban/tests/files/ignorecommand.py b/fail2ban/tests/files/ignorecommand.py index 473980ec..7011b51b 100755 --- a/fail2ban/tests/files/ignorecommand.py +++ b/fail2ban/tests/files/ignorecommand.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env fail2ban-python import sys if sys.argv[1] == "10.0.0.1": exit(0) diff --git a/fail2ban/tests/misctestcase.py b/fail2ban/tests/misctestcase.py index df347e77..b910d94c 100644 --- a/fail2ban/tests/misctestcase.py +++ b/fail2ban/tests/misctestcase.py @@ -73,7 +73,7 @@ class HelpersTest(unittest.TestCase): def _getSysPythonVersion(): import subprocess, locale - sysVerCmd = "python -c 'import sys; print(tuple(sys.version_info))'" + sysVerCmd = "fail2ban-python -c 'import sys; print(tuple(sys.version_info))'" if sys.version_info >= (2,7): sysVer = subprocess.check_output(sysVerCmd, shell=True) else: @@ -144,6 +144,10 @@ class SetupTest(unittest.TestCase): 'etc/fail2ban/jail.conf'): self.assertTrue(os.path.exists(os.path.join(tmp, f)), msg="Can't find %s" % f) + self.assertEqual( + os.path.realpath(os.path.join(tmp, 'usr/local/bin/fail2ban-python')), + os.path.realpath(sys.executable)) + finally: # clean up shutil.rmtree(tmp) diff --git a/setup.py b/setup.py index 5579c981..fa66d4d6 100755 --- a/setup.py +++ b/setup.py @@ -38,12 +38,46 @@ except ImportError: # python 2.x from distutils.command.build_py import build_py from distutils.command.build_scripts import build_scripts +# all versions +from distutils.command.install_scripts import install_scripts + import os from os.path import isfile, join, isdir, realpath import sys import warnings from glob import glob + +def updatePyExec(bindir, executable=None): + """Update fail2ban-python link to current python version (where f2b-modules located/installed) + """ + bindir = os.path.realpath(bindir) + if executable is None: + executable = sys.executable + pypath = os.path.join(bindir, 'fail2ban-python') + # if not exists or point to another version - update link: + isfile = os.path.isfile(pypath) + if not isfile or os.path.realpath(pypath) != os.path.realpath(executable): + if isfile: + os.unlink(pypath) + os.symlink(executable, pypath) + + +# Wrapper to install python binding (to current python version): +class install_scripts_f2b(install_scripts): + + def get_outputs(self): + outputs = install_scripts.get_outputs(self) + fn = None + for fn in outputs: + if os.path.basename(fn) == 'fail2ban-server': + break + bindir = os.path.dirname(fn) + print('creating fail2ban-python binding -> %s' % (bindir,)) + updatePyExec(bindir) + return outputs + + if setuptools and "test" in sys.argv: import logging logSys = logging.getLogger("fail2ban") @@ -99,12 +133,16 @@ setup( url = "http://www.fail2ban.org", license = "GPL", platforms = "Posix", - cmdclass = {'build_py': build_py, 'build_scripts': build_scripts}, + cmdclass = { + 'build_py': build_py, 'build_scripts': build_scripts, + 'install_scripts': install_scripts_f2b + }, scripts = [ 'bin/fail2ban-client', 'bin/fail2ban-server', 'bin/fail2ban-regex', 'bin/fail2ban-testcases', + # 'bin/fail2ban-python', -- link (binary), will be installed via install_scripts_f2b wrapper ], packages = [ 'fail2ban',