From 1e39c2600cc2306329aef9bb5ddddf4a27e48fad Mon Sep 17 00:00:00 2001 From: sebres Date: Fri, 22 Dec 2017 17:21:11 +0100 Subject: [PATCH] cherry-pick from 0.11: changes in updateDb because it can be executed after repair, and some tables can be missing. --- fail2ban/server/database.py | 30 +++++++++++++++++++++--------- fail2ban/tests/databasetestcase.py | 2 +- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/fail2ban/server/database.py b/fail2ban/server/database.py index f301fdf8..5e23fedc 100644 --- a/fail2ban/server/database.py +++ b/fail2ban/server/database.py @@ -331,6 +331,12 @@ class Fail2BanDb(object): def createDb(self, cur, incremental=False): return self._createDb(cur, incremental); + def _tableExists(self, cur, table): + cur.execute("select 1 where exists (" + "select 1 from sqlite_master WHERE type='table' AND name=?)", (table,)) + res = cur.fetchone() + return res is not None and res[0] + @commitandrollback def updateDb(self, cur, version): """Update an existing database, called during initialisation. @@ -340,14 +346,14 @@ class Fail2BanDb(object): if version > Fail2BanDb.__version__: raise NotImplementedError( "Attempt to travel to future version of database ...how did you get here??") + try: + logSys.info("Upgrade database: %s from version '%r'", self._dbBackupFilename, version) + if not os.path.isfile(self._dbBackupFilename): + shutil.copyfile(self.filename, self._dbBackupFilename) + logSys.info(" Database backup created: %s", self._dbBackupFilename) - logSys.info("Uprade database: %s", self._dbBackupFilename) - if not os.path.isfile(self._dbBackupFilename): - shutil.copyfile(self.filename, self._dbBackupFilename) - logSys.info(" Database backup created: %s", self._dbBackupFilename) - - if version < 2: - cur.executescript("BEGIN TRANSACTION;" + if version < 2 and self._tableExists(cur, "logs"): + cur.executescript("BEGIN TRANSACTION;" "CREATE TEMPORARY TABLE logs_temp AS SELECT * FROM logs;" "DROP TABLE logs;" "%s;" @@ -356,8 +362,14 @@ class Fail2BanDb(object): "UPDATE fail2banDb SET version = 2;" "COMMIT;" % Fail2BanDb._CREATE_TABS['logs']) - cur.execute("SELECT version FROM fail2banDb LIMIT 1") - return cur.fetchone()[0] + cur.execute("SELECT version FROM fail2banDb LIMIT 1") + return cur.fetchone()[0] + except Exception as e: + # if still failed, just recreate database as fallback: + logSys.error("Failed to upgrade database '%s': %s", + self._dbFilename, e.args[0], + exc_info=logSys.getEffectiveLevel() <= 10) + raise @commitandrollback def addJail(self, cur, jail): diff --git a/fail2ban/tests/databasetestcase.py b/fail2ban/tests/databasetestcase.py index 5ac590f5..5124d75e 100644 --- a/fail2ban/tests/databasetestcase.py +++ b/fail2ban/tests/databasetestcase.py @@ -144,7 +144,7 @@ class DatabaseTest(LogCaptureTestCase): self.assertEqual(len(self.db.getJailNames()), 1) else: # recreated: self.assertLogged("Repair seems to be failed", - "New database created.", all=True) + "Check integrity", "New database created.", all=True) self.assertEqual(len(self.db.getLogPaths()), 0) self.assertEqual(len(self.db.getJailNames()), 0) finally: