introduced new option `-t` or `--test` to test configuration resp. start server only if configuration is clean (not skip wrong configured jails if option `-t` specified);

pull/1619/head
sebres 2016-11-22 17:08:44 +01:00
parent 3e9852d4d2
commit fdac44ca58
5 changed files with 86 additions and 32 deletions

View File

@ -72,9 +72,9 @@ class Configurator:
def getEarlyOptions(self):
return self.__fail2ban.getEarlyOptions()
def getOptions(self, jail=None, updateMainOpt=None):
def getOptions(self, jail=None, updateMainOpt=None, ignoreWrong=True):
self.__fail2ban.getOptions(updateMainOpt)
return self.__jails.getOptions(jail)
return self.__jails.getOptions(jail, ignoreWrong=ignoreWrong)
def convertToProtocol(self):
self.__streams["general"] = self.__fail2ban.convert()

View File

@ -47,6 +47,7 @@ class Fail2banCmdLine():
def __init__(self):
self._argv = self._args = None
self._configurator = None
self.cleanConfOnly = False
self.resetConf()
def resetConf(self):
@ -101,6 +102,7 @@ class Fail2banCmdLine():
output(" --logtarget <FILE>|STDOUT|STDERR|SYSLOG")
output(" --syslogsocket auto|<FILE>")
output(" -d dump configuration. For debugging")
output(" -t, --test test configuration (can be also specified with start parameters)")
output(" -i interactive mode")
output(" -v increase verbosity")
output(" -q decrease verbosity")
@ -136,6 +138,9 @@ class Fail2banCmdLine():
self._conf[ o[2:] ] = opt[1]
elif o == "-d":
self._conf["dump"] = True
elif o == "-t" or o == "--test":
self.cleanConfOnly = True
self._conf["test"] = True
elif o == "-v":
self._conf["verbose"] += 1
elif o == "-q":
@ -173,8 +178,8 @@ class Fail2banCmdLine():
# Reads the command line options.
try:
cmdOpts = 'hc:s:p:xfbdviqV'
cmdLongOpts = ['loglevel=', 'logtarget=', 'syslogsocket=', 'async', 'timeout=', 'help', 'version']
cmdOpts = 'hc:s:p:xfbdtviqV'
cmdLongOpts = ['loglevel=', 'logtarget=', 'syslogsocket=', 'test', 'async', 'timeout=', 'help', 'version']
optList, self._args = getopt.getopt(self._argv[1:], cmdOpts, cmdLongOpts)
except getopt.GetoptError:
self.dispUsage()
@ -225,13 +230,30 @@ class Fail2banCmdLine():
logSys.info("Using pid file %s, [%s] logging to %s",
self._conf["pidfile"], logging.getLevelName(llev), self._conf["logtarget"])
readcfg = True
if self._conf.get("dump", False):
if readcfg:
ret, stream = self.readConfig()
readcfg = False
self.dumpConfig(stream)
if not self._conf.get("test", False):
return ret
if self._conf.get("test", False):
if readcfg:
readcfg = False
ret, stream = self.readConfig()
if not ret:
raise ServerExecutionException("ERROR: test configuration failed")
# exit after test if no commands specified (test only):
if not len(self._args):
output("OK: configuration test is successful")
return ret
# Nothing to do here, process in client/server
return None
except ServerExecutionException:
raise
except Exception as e:
output("ERROR: %s" % (e,))
if verbose > 2:
@ -246,7 +268,8 @@ class Fail2banCmdLine():
try:
self.configurator.Reload()
self.configurator.readAll()
ret = self.configurator.getOptions(jail, self._conf)
ret = self.configurator.getOptions(jail, self._conf,
ignoreWrong=not self.cleanConfOnly)
self.configurator.convertToProtocol()
stream = self.configurator.getConfigStream()
except Exception as e:

View File

@ -144,6 +144,8 @@ class Fail2banServer(Fail2banCmdLine):
return cli
def start(self, argv):
server = None
try:
# Command line options
ret = self.initCmdLine(argv)
if ret is not None:
@ -163,8 +165,6 @@ class Fail2banServer(Fail2banCmdLine):
return cli.start(argv)
# Start the server:
server = None
try:
from ..server.utils import Utils
# background = True, if should be new process running in background, otherwise start in foreground
# process will be forked in daemonize, inside of Server module.

View File

@ -54,7 +54,7 @@ class JailsReader(ConfigReader):
self.__jails = list()
return ConfigReader.read(self, "jail")
def getOptions(self, section=None):
def getOptions(self, section=None, ignoreWrong=True):
"""Reads configuration for jail(s) and adds enabled jails to __jails
"""
opts = []
@ -66,7 +66,7 @@ class JailsReader(ConfigReader):
sections = [ section ]
# Get the options of all jails.
parse_status = None
parse_status = 0
for sec in sections:
if sec == 'INCLUDES':
continue
@ -78,14 +78,15 @@ class JailsReader(ConfigReader):
if ret:
if jail.isEnabled():
# at least one jail was successful:
parse_status = True
parse_status |= 1
# We only add enabled jails
self.__jails.append(jail)
else:
logSys.error("Errors in jail %r. Skipping..." % sec)
logSys.error("Errors in jail %r.%s", sec, " Skipping..." if ignoreWrong else "")
self.__jails.append(jail)
if parse_status is None: parse_status = False
return True if parse_status != False else False
# at least one jail was invalid:
parse_status |= 2
return ((ignoreWrong and parse_status & 1) or not (parse_status & 2))
def convert(self, allow_no_files=False):
"""Convert read before __opts and jails to the commands stream

View File

@ -675,6 +675,36 @@ class Fail2banServerTest(Fail2banClientServerBase):
self.pruneLog()
os.remove(pjoin(tmp, "f2b.sock"))
@with_tmpdir
@with_kill_srv
def testServerTestFailStart(self, tmp):
# started directly here, so prevent overwrite test cases logger with "INHERITED"
startparams = _start_params(tmp, logtarget="INHERITED")
cfg = pjoin(tmp, "config")
# test configuration is correct:
self.pruneLog("[test-phase 0]")
self.execSuccess(startparams, "--test")
self.assertLogged("OK: configuration test is successful")
# append one wrong configured jail:
_write_file(pjoin(cfg, "jail.conf"), "a", "", "[broken-jail]",
"", "filter = broken-jail-filter", "enabled = true")
# first try test config:
self.pruneLog("[test-phase 0a]")
self.execFailed(startparams, "--test")
self.assertLogged("Unable to read the filter 'broken-jail-filter'",
"Errors in jail 'broken-jail'.",
"ERROR: test configuration failed", all=True)
# failed to start with test config:
self.pruneLog("[test-phase 0b]")
self.execFailed(startparams, "-t", "start")
self.assertLogged("Unable to read the filter 'broken-jail-filter'",
"Errors in jail 'broken-jail'.",
"ERROR: test configuration failed", all=True)
@with_tmpdir
def testKillAfterStart(self, tmp):
try: