Merge pull request #470 from grooverdan/flush-logs

BF: create flushlogs command to prevent logrotation clobbering logtarget...
pull/481/head
Steven Hiscocks 2013-12-06 16:30:16 -08:00
commit 7115f64f83
7 changed files with 50 additions and 3 deletions

View File

@ -22,6 +22,8 @@ ver. 0.8.12 (2013/12/XX) - things-can-only-get-better
- smtps not a IANA standard and has been removed from Arch. Replaced with - smtps not a IANA standard and has been removed from Arch. Replaced with
465. Thanks Stefan. Closes gh-447 465. Thanks Stefan. Closes gh-447
- mysqld-syslog-iptables rule was too long. Part of gh-447. - mysqld-syslog-iptables rule was too long. Part of gh-447.
- add 'flushlogs' command to allow logrotation without clobbering logtarget
settings. Closes gh-458, Debian bug #697333, Redhat bug #891798.
- Enhancements: - Enhancements:
- long names on jails documented based on iptables limit of 30 less - long names on jails documented based on iptables limit of 30 less

View File

@ -63,6 +63,8 @@ class Beautifier:
msg = "Jail stopped" msg = "Jail stopped"
elif inC[0] == "add": elif inC[0] == "add":
msg = "Added jail " + response msg = "Added jail " + response
elif inC[0] == "flushlogs":
msg = "logs: " + response
elif inC[0:1] == ['status']: elif inC[0:1] == ['status']:
if len(inC) > 1: if len(inC) > 1:
# Create IP list # Create IP list

View File

@ -43,6 +43,7 @@ protocol = [
["get loglevel", "gets the logging level"], ["get loglevel", "gets the logging level"],
["set logtarget <TARGET>", "sets logging target to <TARGET>. Can be STDOUT, STDERR, SYSLOG or a file"], ["set logtarget <TARGET>", "sets logging target to <TARGET>. Can be STDOUT, STDERR, SYSLOG or a file"],
["get logtarget", "gets logging target"], ["get logtarget", "gets logging target"],
["flushlogs", "flushes the logtarget if a file and reopens it. For log rotation."],
['', "JAIL CONTROL", ""], ['', "JAIL CONTROL", ""],
["add <JAIL> <BACKEND>", "creates <JAIL> using <BACKEND>"], ["add <JAIL> <BACKEND>", "creates <JAIL> using <BACKEND>"],
["start <JAIL>", "starts the jail <JAIL>"], ["start <JAIL>", "starts the jail <JAIL>"],

View File

@ -13,6 +13,6 @@
missingok missingok
compress compress
postrotate postrotate
/usr/bin/fail2ban-client set logtarget /var/log/fail2ban.log 1>/dev/null || true /usr/bin/fail2ban-client flushlogs 1>/dev/null || true
endscript endscript
} }

View File

@ -361,7 +361,7 @@ class Server:
# Target should be a file # Target should be a file
try: try:
open(target, "a").close() open(target, "a").close()
hdlr = logging.FileHandler(target) hdlr = logging.handlers.RotatingFileHandler(target)
except IOError: except IOError:
logSys.error("Unable to log to " + target) logSys.error("Unable to log to " + target)
logSys.info("Logging to previous target " + self.__logTarget) logSys.info("Logging to previous target " + self.__logTarget)
@ -401,6 +401,17 @@ class Server:
finally: finally:
self.__loggingLock.release() self.__loggingLock.release()
def flushLogs(self):
if self.__logTarget not in ['STDERR', 'STDOUT', 'SYSLOG']:
for handler in logging.getLogger("fail2ban").handlers:
handler.doRollover()
return "rolled over"
else:
for handler in logging.getLogger("fail2ban").handlers:
handler.flush()
return "flushed"
def __createDaemon(self): # pragma: no cover def __createDaemon(self): # pragma: no cover
""" Detach a process from the controlling terminal and run it in the """ Detach a process from the controlling terminal and run it in the
background as a daemon. background as a daemon.

View File

@ -92,6 +92,8 @@ class Transmitter:
value = command[1] value = command[1]
time.sleep(int(value)) time.sleep(int(value))
return None return None
elif command[0] == "flushlogs":
return self.__server.flushLogs()
elif command[0] == "set": elif command[0] == "set":
return self.__commandSet(command[1:]) return self.__commandSet(command[1:])
elif command[0] == "get": elif command[0] == "get":

View File

@ -25,7 +25,7 @@ __copyright__ = "Copyright (c) 2004 Cyril Jaquier"
__license__ = "GPL" __license__ = "GPL"
import unittest, socket, time, tempfile, os, sys import unittest, socket, time, tempfile, os, sys
from server.server import Server from server.server import Server, logSys
from server.jail import Jail from server.jail import Jail
from common.exceptions import UnknownJailException from common.exceptions import UnknownJailException
@ -521,6 +521,35 @@ class TransmitterLogging(TransmitterBase):
self.setGetTest("loglevel", "0", 0) self.setGetTest("loglevel", "0", 0)
self.setGetTestNOK("loglevel", "Bird") self.setGetTestNOK("loglevel", "Bird")
def testFlushLogs(self):
self.assertEqual(self.transm.proceed(["flushlogs"]), (0, "rolled over"))
try:
f, fn = tempfile.mkstemp("fail2ban.log")
os.close(f)
self.server.setLogLevel(2)
self.assertEqual(self.transm.proceed(["set", "logtarget", fn]), (0, fn))
logSys.warn("Before file moved")
try:
f2, fn2 = tempfile.mkstemp("fail2ban.log")
os.close(f2)
os.rename(fn, fn2)
logSys.warn("After file moved")
self.assertEqual(self.transm.proceed(["flushlogs"]), (0, "rolled over"))
logSys.warn("After flushlogs")
with open(fn2,'r') as f:
self.assertTrue(f.next().endswith("Before file moved\n"))
self.assertTrue(f.next().endswith("After file moved\n"))
self.assertRaises(StopIteration, f.next)
with open(fn,'r') as f:
self.assertTrue(f.next().endswith("After flushlogs\n"))
self.assertRaises(StopIteration, f.next)
finally:
os.remove(fn2)
finally:
os.remove(fn)
self.assertEqual(self.transm.proceed(["set", "logtarget", "STDERR"]), (0, "STDERR"))
self.assertEqual(self.transm.proceed(["flushlogs"]), (0, "flushed"))
class JailTests(unittest.TestCase): class JailTests(unittest.TestCase):