code review, test case extended;

pull/716/head
sebres 2014-12-02 11:57:43 +01:00
parent 697da99f8f
commit 4dbc77dbbb
2 changed files with 71 additions and 14 deletions

View File

@ -559,7 +559,7 @@ class FileFilter(Filter):
# #
# @param path log file path # @param path log file path
def addLogPath(self, path, tail = False): def addLogPath(self, path, tail=False):
if self.containsLogPath(path): if self.containsLogPath(path):
logSys.error(path + " already exists") logSys.error(path + " already exists")
else: else:
@ -655,7 +655,7 @@ class FileFilter(Filter):
# MyTime.time()-self.findTime. When a failure is detected, a FailTicket # MyTime.time()-self.findTime. When a failure is detected, a FailTicket
# is created and is added to the FailManager. # is created and is added to the FailManager.
def getFailures(self, filename, startTime = None): def getFailures(self, filename, startTime=None):
container = self.getFileContainer(filename) container = self.getFileContainer(filename)
if container is None: if container is None:
logSys.error("Unable to get failures in " + filename) logSys.error("Unable to get failures in " + filename)
@ -673,14 +673,19 @@ class FileFilter(Filter):
logSys.exception(e) logSys.exception(e)
return False return False
except OSError, e: # pragma: no cover - Requires implemention error in FileContainer to generate except OSError, e: # pragma: no cover - Requires implemention error in FileContainer to generate
logSys.error("Internal errror in FileContainer open method - please report as a bug to https://github.com/fail2ban/fail2ban/issues") logSys.error("Internal error in FileContainer open method - please report as a bug to https://github.com/fail2ban/fail2ban/issues")
logSys.exception(e) logSys.exception(e)
return False return False
# prevent completely read of big files first time (after start of service), initial seek to start time using half-interval search algorithm: # prevent completely read of big files first time (after start of service), initial seek to start time using half-interval search algorithm:
if container.getPos() == 0 and startTime is not None: if container.getPos() == 0 and startTime is not None:
# startTime = MyTime.time() - self.getFindTime() try:
self.seekToTime(container, startTime) # startTime = MyTime.time() - self.getFindTime()
self.seekToTime(container, startTime)
except Exception, e: # pragma: no cover
logSys.error("Error during seek to start time in \"%s\"", filename)
logSys.exception(e)
return False
# yoh: has_content is just a bool, so do not expect it to # yoh: has_content is just a bool, so do not expect it to
# change -- loop is exited upon break, and is not entered at # change -- loop is exited upon break, and is not entered at
@ -717,7 +722,7 @@ class FileFilter(Filter):
cntr = 0 cntr = 0
unixTime = None unixTime = None
lasti = 0 lasti = 0
movecntr = 3 movecntr = 1
while maxp > minp: while maxp > minp:
i = int(minp + (maxp - minp) / 2) i = int(minp + (maxp - minp) / 2)
pos = container.seek(i) pos = container.seek(i)
@ -726,7 +731,8 @@ class FileFilter(Filter):
lncntr = 5; lncntr = 5;
dateTimeMatch = None dateTimeMatch = None
llen = 0 llen = 0
i = pos if lastpos == pos:
i = pos
while True: while True:
line = container.readline() line = container.readline()
if not line: if not line:
@ -763,6 +769,7 @@ class FileFilter(Filter):
lastpos = container.seek(lastFew, False) lastpos = container.seek(lastFew, False)
else: else:
lastpos = container.seek(lastpos, False) lastpos = container.seek(lastpos, False)
container.setPos(lastpos)
if logSys.getEffectiveLevel() <= logging.DEBUG: if logSys.getEffectiveLevel() <= logging.DEBUG:
logSys.debug("Position %s from %s, found time %s (%s) within %s seeks", lastpos, fs, unixTime, logSys.debug("Position %s from %s, found time %s (%s) within %s seeks", lastpos, fs, unixTime,
(datetime.datetime.fromtimestamp(unixTime).strftime("%Y-%m-%d %H:%M:%S") if unixTime is not None else ''), cntr) (datetime.datetime.fromtimestamp(unixTime).strftime("%Y-%m-%d %H:%M:%S") if unixTime is not None else ''), cntr)
@ -943,10 +950,6 @@ class DNSUtils:
logSys.warning("Unable to find a corresponding IP address for %s: %s" logSys.warning("Unable to find a corresponding IP address for %s: %s"
% (dns, e)) % (dns, e))
return list() return list()
except socket.error, e:
logSys.warning("Socket error raised trying to resolve hostname %s: %s"
% (dns, e))
return list()
@staticmethod @staticmethod
def searchIP(text): def searchIP(text):
@ -967,7 +970,7 @@ class DNSUtils:
try: try:
socket.inet_aton(s[0]) socket.inet_aton(s[0])
return True return True
except socket.error: except socket.error: # pragma: no cover
return False return False
@staticmethod @staticmethod

View File

@ -27,7 +27,7 @@ import unittest
import getpass import getpass
import os import os
import sys import sys
import time import time, datetime
import tempfile import tempfile
import uuid import uuid
@ -38,7 +38,7 @@ except ImportError:
from ..server.jail import Jail from ..server.jail import Jail
from ..server.filterpoll import FilterPoll from ..server.filterpoll import FilterPoll
from ..server.filter import Filter, FileFilter, DNSUtils from ..server.filter import Filter, FileFilter, FileContainer, DNSUtils
from ..server.failmanager import FailManagerEmpty from ..server.failmanager import FailManagerEmpty
from ..server.mytime import MyTime from ..server.mytime import MyTime
from .utils import setUpMyTime, tearDownMyTime, mtimesleep, LogCaptureTestCase from .utils import setUpMyTime, tearDownMyTime, mtimesleep, LogCaptureTestCase
@ -314,6 +314,60 @@ class LogFileFilterPoll(unittest.TestCase):
self.assertTrue(self.filter.isModified(LogFileFilterPoll.FILENAME)) self.assertTrue(self.filter.isModified(LogFileFilterPoll.FILENAME))
self.assertFalse(self.filter.isModified(LogFileFilterPoll.FILENAME)) self.assertFalse(self.filter.isModified(LogFileFilterPoll.FILENAME))
def testSeekToTime(self):
fname = tempfile.mktemp(prefix='tmp_fail2ban', suffix='.log')
tm = lambda time: datetime.datetime.fromtimestamp(time).strftime("%Y-%m-%d %H:%M:%S")
time = 1417512352
f = open(fname, 'w')
fc = FileContainer(fname, self.filter.getLogEncoding())
fc.open()
fc.setPos(0); self.filter.seekToTime(fc, time)
try:
f.flush()
# empty :
fc.setPos(0); self.filter.seekToTime(fc, time)
self.assertEqual(fc.getPos(), 0)
# one entry with exact time:
f.write("%s [sshd] error: PAM: failure len 1\n" % tm(time))
f.flush()
fc.setPos(0); self.filter.seekToTime(fc, time)
# one entry with smaller time:
f.seek(0)
f.write("%s [sshd] error: PAM: failure len 1\n" % tm(time - 10))
f.flush()
fc.setPos(0); self.filter.seekToTime(fc, time)
self.assertEqual(fc.getPos(), 0)
f.write("%s [sshd] error: PAM: failure len 3 2 1\n" % tm(time - 9))
f.flush()
fc.setPos(0); self.filter.seekToTime(fc, time)
self.assertEqual(fc.getPos(), 0)
# add exact time between:
f.write("%s [sshd] error: PAM: failure\n" % tm(time - 1))
f.flush()
fc.setPos(0); self.filter.seekToTime(fc, time)
self.assertEqual(fc.getPos(), 110)
# stil one exact line:
f.write("%s [sshd] error: PAM: Authentication failure\n" % tm(time))
f.write("%s [sshd] error: PAM: failure len 1\n" % tm(time))
f.flush()
fc.setPos(0); self.filter.seekToTime(fc, time)
self.assertEqual(fc.getPos(), 110)
# add something hereafter:
f.write("%s [sshd] error: PAM: failure len 3 2 1\n" % tm(time + 2))
f.write("%s [sshd] error: PAM: Authentication failure\n" % tm(time + 3))
f.flush()
fc.setPos(0); self.filter.seekToTime(fc, time)
self.assertEqual(fc.getPos(), 110)
# add something hereafter:
f.write("%s [sshd] error: PAM: failure\n" % tm(time + 9))
f.write("%s [sshd] error: PAM: failure len 3 2 1\n" % tm(time + 9))
f.flush()
fc.setPos(0); self.filter.seekToTime(fc, time)
self.assertEqual(fc.getPos(), 110)
finally:
fc.close()
_killfile(f, fname)
class LogFileMonitor(LogCaptureTestCase): class LogFileMonitor(LogCaptureTestCase):
"""Few more tests for FilterPoll API """Few more tests for FilterPoll API