From 6787c655f9fe3976c5dd9ea5ca82caffd5a09b8c Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Jul 2013 19:10:29 +0200 Subject: [PATCH 01/55] skip lost+found directories --- dbclean/dbclean.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dbclean/dbclean.py b/dbclean/dbclean.py index 6985414..7643be7 100755 --- a/dbclean/dbclean.py +++ b/dbclean/dbclean.py @@ -118,6 +118,8 @@ def __str__( self ): if dir.startswith( '.' ): # skip hidden directories continue + if dir == 'lost+found': + continue fullpath = os.path.normpath( datadir + '/' + dir ) if not os.path.isdir( fullpath ): From e67198c57c5360b14f451497dc221c897a8da9b8 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Jul 2013 19:12:38 +0200 Subject: [PATCH 02/55] pep8 cleanup --- dbclean/dbclean.py | 74 +++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/dbclean/dbclean.py b/dbclean/dbclean.py index 7643be7..1582164 100755 --- a/dbclean/dbclean.py +++ b/dbclean/dbclean.py @@ -36,7 +36,7 @@ help="""Additional config-files to use (default: %(default)s). Can be given multiple times to name multiple config-files.""") parser.add_argument('section', action='store', type=str, - help="Section in the config-file to use." ) + help="Section in the config-file to use.") args = parser.parse_args() if args.section=='DEFAULT': @@ -78,104 +78,104 @@ class backup(): files = [] - def __init__( self, time, base, file ): + def __init__(self, time, base, file): self.time = time self.base = base self.files = [ file ] - def add( self, file ): - self.files.append( file ) + def add(self, file): + self.files.append(file) - def is_daily( self ): + def is_daily(self): if self.time[3] == 0: return True else: return False - def is_monthly( self ): + def is_monthly(self): if self.is_daily() and self.time[2] == 1: return True else: return False - def is_yearly( self ): + def is_yearly(self): if self.is_monthly() and self.time[1] == 1: return True else: return False - def remove( self ): + def remove(self): for file in self.files: - os.remove( file ) + os.remove(file) - def __str__( self ): + def __str__(self): return "%s in %s" %(self.files, self.base) now = time.time() # loop through each dir in datadir -for dir in os.listdir( datadir ): - if dir.startswith( '.' ): +for dir in os.listdir(datadir): + if dir.startswith('.'): # skip hidden directories continue if dir == 'lost+found': continue - fullpath = os.path.normpath( datadir + '/' + dir ) - if not os.path.isdir( fullpath ): - print( "Warning: %s: Not a directory." % (fullpath) ) + fullpath = os.path.normpath(datadir + '/' + dir) + if not os.path.isdir(fullpath): + print("Warning: %s: Not a directory." % (fullpath)) continue - os.chdir( fullpath ) + os.chdir(fullpath) backups = {} - files = os.listdir( '.' ) + files = os.listdir('.') files.sort() for file in files: - filestamp = file.split( '.' )[0] + filestamp = file.split('.')[0] timestamp = '' try: - timestamp = time.strptime( filestamp, timeformat ) + timestamp = time.strptime(filestamp, timeformat) except ValueError as e: - print( '%s: %s' %(file, e) ) + print('%s: %s' %(file, e)) - if timestamp not in list( backups.keys() ): - backups[timestamp] = backup( timestamp, fullpath, file ) + if timestamp not in list(backups.keys()): + backups[timestamp] = backup(timestamp, fullpath, file) else: - backups[timestamp].add( file ) + backups[timestamp].add(file) for stamp in list(backups.keys()): bck = backups[stamp] - bck_seconds = calendar.timegm( stamp ) + bck_seconds = calendar.timegm(stamp) - if bck_seconds > now - ( hourly * 3600 ): -# print ( "%s is hourly and will be kept" % ( time.asctime( stamp ) ) ) + if bck_seconds > now - (hourly * 3600): +# print ("%s is hourly and will be kept" % (time.asctime(stamp))) continue # else: -# print ("%s is hourly but to old." % ( time.asctime( stamp ) ) ) +# print ("%s is hourly but to old." % (time.asctime(stamp))) if bck.is_daily(): - if bck_seconds > now - ( daily * 86400 ): -# print( "%s is daily and will be kept." % ( time.asctime( stamp ) ) ) + if bck_seconds > now - (daily * 86400): +# print("%s is daily and will be kept." % (time.asctime(stamp))) continue # else: -# print ("%s is daily but to old." % ( time.asctime( stamp ) ) ) +# print ("%s is daily but to old." % (time.asctime(stamp))) if bck.is_monthly(): - if bck_seconds > now - ( monthly * 2678400 ): -# print( "%s is monthly and will be kept." % ( time.asctime( stamp ) ) ) + if bck_seconds > now - (monthly * 2678400): +# print("%s is monthly and will be kept." % (time.asctime(stamp))) continue # else: -# print ("%s is monthly but to old." % ( time.asctime( stamp ) ) ) +# print ("%s is monthly but to old." % (time.asctime(stamp))) if bck.is_yearly(): - if bck_seconds > now - ( yearly * 31622400 ): -# print( "%s is yearly and will be kept." % ( time.asctime( stamp ) ) ) + if bck_seconds > now - (yearly * 31622400): +# print("%s is yearly and will be kept." % (time.asctime(stamp))) continue # else: -# print ("%s is yearly but to old." % ( time.asctime( stamp ) ) ) -# print( "%s will be removed." % ( time.asctime( stamp ) ) ) +# print ("%s is yearly but to old." % (time.asctime(stamp))) +# print("%s will be removed." % (time.asctime(stamp))) bck.remove() From 718bd7925ee36ba1cc21ac75dfd151c54e325e6d Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Jul 2013 19:22:14 +0200 Subject: [PATCH 03/55] massive pep8 cleanup --- dbclean/dbclean.py | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/dbclean/dbclean.py b/dbclean/dbclean.py index 1582164..6f9142d 100755 --- a/dbclean/dbclean.py +++ b/dbclean/dbclean.py @@ -9,7 +9,7 @@ Please see the README file for how to use this script and supported features. You might also try calling this program with '--help'. -Copyright 2009 Mathias Ertl +Copyright 2009 - 2013 Mathias Ertl This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,21 +25,31 @@ along with this program. If not, see . """ -import os, time, sys, calendar, configparser, argparse +import argparse +import calendar +import configparser +import os +import sys +import time -config_file = ['/etc/dbclean/dbclean.conf', os.path.expanduser('~/.dbclean.conf')] +config_file = [ + '/etc/dbclean/dbclean.conf', + os.path.expanduser('~/.dbclean.conf') +] parser = argparse.ArgumentParser(version="%prog 1.0", - description = """Cleanup regular database dumps created by dbdump. This script keeps backups - at given intervals for a given amount of time.""") -parser.add_argument('-c', '--config', type=str, dest='config', action='append', default=config_file, - help="""Additional config-files to use (default: %(default)s). Can be given multiple times - to name multiple config-files.""") + description="""Cleanup regular database dumps created by dbdump. This +script keeps backups at given intervals for a given amount of time.""") +parser.add_argument( + '-c', '--config', type=str, dest='config', action='append', + default=config_file, help="""Additional config-files to use (default: + %(default)s). Can be given multiple times to name multiple + config-files.""") parser.add_argument('section', action='store', type=str, - help="Section in the config-file to use.") + help="Section in the config-file to use.") args = parser.parse_args() -if args.section=='DEFAULT': +if args.section == 'DEFAULT': parser.error("--section must not be 'DEFAULT'.") config = configparser.SafeConfigParser({ @@ -52,10 +62,12 @@ # check validity of config-file: if args.section not in config: - print("Error: %s: No section found with that name." % args.section, file=sys.stderr) + print("Error: %s: No section found with that name." % args.section, + file=sys.stderr) sys.exit(1) if 'datadir' not in config[args.section]: - print("Error: %s: Section does not contain option 'datadir'." % args.section, file=sys.stderr) + print("Error: %s: Section does not contain option 'datadir'." % args.section, + file=sys.stderr) sys.exit(1) # get directory containing backups: @@ -75,13 +87,14 @@ monthly = int(config[args.section]['monthly']) yearly = int(config[args.section]['yearly']) + class backup(): files = [] def __init__(self, time, base, file): self.time = time self.base = base - self.files = [ file ] + self.files = [file] def add(self, file): self.files.append(file) @@ -109,7 +122,7 @@ def remove(self): os.remove(file) def __str__(self): - return "%s in %s" %(self.files, self.base) + return "%s in %s" % (self.files, self.base) now = time.time() @@ -138,14 +151,13 @@ def __str__(self): try: timestamp = time.strptime(filestamp, timeformat) except ValueError as e: - print('%s: %s' %(file, e)) + print('%s: %s' % (file, e)) if timestamp not in list(backups.keys()): backups[timestamp] = backup(timestamp, fullpath, file) else: backups[timestamp].add(file) - for stamp in list(backups.keys()): bck = backups[stamp] bck_seconds = calendar.timegm(stamp) From b76cbbf0ceb9830f4a6d3e8aeca55841d9c4bfec Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Jul 2013 19:26:08 +0200 Subject: [PATCH 04/55] add error function shortcut --- dbclean/dbclean.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/dbclean/dbclean.py b/dbclean/dbclean.py index 6f9142d..78ea0e5 100755 --- a/dbclean/dbclean.py +++ b/dbclean/dbclean.py @@ -32,6 +32,10 @@ import sys import time + +def err(msg, *args): + print(msg % args, file=sys.stderr) + config_file = [ '/etc/dbclean/dbclean.conf', os.path.expanduser('~/.dbclean.conf') @@ -62,12 +66,10 @@ # check validity of config-file: if args.section not in config: - print("Error: %s: No section found with that name." % args.section, - file=sys.stderr) + err("Error: %s: No section found with that name.", args.section) sys.exit(1) if 'datadir' not in config[args.section]: - print("Error: %s: Section does not contain option 'datadir'." % args.section, - file=sys.stderr) + err("Error: %s: Section does not contain option 'datadir'.", args.section) sys.exit(1) # get directory containing backups: @@ -75,10 +77,10 @@ # check that given directory exists and is a directory: if not os.path.exists(datadir): - print("Error: %s: No such directory." % (datadir), file=sys.stderr) + err("Error: %s: No such directory.", datadir) sys.exit(1) elif not os.path.isdir(datadir): - print("Error: %s: Not a directory." % (datadir), file=sys.stderr) + err("Error: %s: Not a directory.", datadir) sys.exit(1) timeformat = config[args.section]['format'] @@ -136,7 +138,7 @@ def __str__(self): fullpath = os.path.normpath(datadir + '/' + dir) if not os.path.isdir(fullpath): - print("Warning: %s: Not a directory." % (fullpath)) + print("Warning: %s: Not a directory." % fullpath) continue os.chdir(fullpath) From 7ac944aaa58946ea922b8686ead8d091138ca808 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Jul 2013 19:33:09 +0200 Subject: [PATCH 05/55] update README --- dbclean/README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbclean/README b/dbclean/README index 443ff84..aef17c7 100644 --- a/dbclean/README +++ b/dbclean/README @@ -8,7 +8,7 @@ are matched to those of dbdump, so they work together. === Installation === Simply check out the git-repository: - git clone http://git.git.fsinf.at/fsinf/db-backup.git + git clone https://git.fsinf.at/fsinf/db-backup.git If you don't want to specify the full path, you can of course copy dbclean.py somewhere in your path (/usr/local/bin is usually good). @@ -22,5 +22,5 @@ A sample configuration file is included with the source code, see: dbclean.conf.example After that, you can start the script with - dbclean.py --section=example + dbclean.py example where example is the section in your config-file. From ec4d6cdffd94f9c41f0d1a72fd9268d3157858da Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Jul 2013 20:47:15 +0200 Subject: [PATCH 06/55] add support for the 'last' config value (always keep the last N backups) --- dbclean/dbclean.conf.example | 2 ++ dbclean/dbclean.py | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/dbclean/dbclean.conf.example b/dbclean/dbclean.conf.example index ad18a99..2cc52d8 100644 --- a/dbclean/dbclean.conf.example +++ b/dbclean/dbclean.conf.example @@ -4,6 +4,8 @@ # sections. #hourly = 72 #daily = 31 +# Always keep the last three backups +#last = 3 # # NOTE: You can also use the interpolation feature provided by the # ConfigParser python module. The following line is used in the diff --git a/dbclean/dbclean.py b/dbclean/dbclean.py index 78ea0e5..a7f1bcd 100755 --- a/dbclean/dbclean.py +++ b/dbclean/dbclean.py @@ -59,7 +59,8 @@ def err(msg, *args): config = configparser.SafeConfigParser({ 'format': '%%Y-%%m-%%d_%%H:%%M:%%S', 'hourly': '24', 'daily': '31', - 'monthly': '12', 'yearly': '3' + 'monthly': '12', 'yearly': '3', + 'last': '3', }) if not config.read(args.config): parser.error("No config-files could be read.") @@ -88,6 +89,7 @@ def err(msg, *args): daily = int(config[args.section]['daily']) monthly = int(config[args.section]['monthly']) yearly = int(config[args.section]['yearly']) +last = int(config[args.section]['last']) class backup(): @@ -160,7 +162,11 @@ def __str__(self): else: backups[timestamp].add(file) - for stamp in list(backups.keys()): + backup_items = sorted(backups.items(), key=lambda t: t[0]) + if last: # NOTE: if last == 0, the slice returns an empty list! + backup_items = backup_items[:-last] + + for stamp, bck in backup_items: bck = backups[stamp] bck_seconds = calendar.timegm(stamp) From 313e5fd6294c0b8956086d1097797502a5fba503 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Jul 2013 20:49:53 +0200 Subject: [PATCH 07/55] use more telling time-tuple members --- dbclean/dbclean.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dbclean/dbclean.py b/dbclean/dbclean.py index a7f1bcd..842a82d 100755 --- a/dbclean/dbclean.py +++ b/dbclean/dbclean.py @@ -104,19 +104,19 @@ def add(self, file): self.files.append(file) def is_daily(self): - if self.time[3] == 0: + if self.time.tm_hour == 0: return True else: return False def is_monthly(self): - if self.is_daily() and self.time[2] == 1: + if self.is_daily() and self.time.tm_mday == 1: return True else: return False def is_yearly(self): - if self.is_monthly() and self.time[1] == 1: + if self.is_monthly() and self.time.tm_mon == 1: return True else: return False From 1c66751f5c23ea4f53adf929ab5c6e741e0c340c Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Jul 2013 20:51:02 +0200 Subject: [PATCH 08/55] cleanup --- dbclean/dbclean.py | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/dbclean/dbclean.py b/dbclean/dbclean.py index 842a82d..4956559 100755 --- a/dbclean/dbclean.py +++ b/dbclean/dbclean.py @@ -171,31 +171,15 @@ def __str__(self): bck_seconds = calendar.timegm(stamp) if bck_seconds > now - (hourly * 3600): -# print ("%s is hourly and will be kept" % (time.asctime(stamp))) continue -# else: -# print ("%s is hourly but to old." % (time.asctime(stamp))) - if bck.is_daily(): - if bck_seconds > now - (daily * 86400): -# print("%s is daily and will be kept." % (time.asctime(stamp))) + if bck.is_daily() and bck_seconds > now - (daily * 86400): continue -# else: -# print ("%s is daily but to old." % (time.asctime(stamp))) - if bck.is_monthly(): - if bck_seconds > now - (monthly * 2678400): -# print("%s is monthly and will be kept." % (time.asctime(stamp))) + if bck.is_monthly() and bck_seconds > now - (monthly * 2678400): continue -# else: -# print ("%s is monthly but to old." % (time.asctime(stamp))) - if bck.is_yearly(): - if bck_seconds > now - (yearly * 31622400): -# print("%s is yearly and will be kept." % (time.asctime(stamp))) + if bck.is_yearly() and bck_seconds > now - (yearly * 31622400): continue -# else: -# print ("%s is yearly but to old." % (time.asctime(stamp))) -# print("%s will be removed." % (time.asctime(stamp))) bck.remove() From 5b4b93cfdc6a70eeb7c729f60349166603b03ef8 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Jul 2013 20:52:40 +0200 Subject: [PATCH 09/55] continue when we can't parse timestamp --- dbclean/dbclean.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dbclean/dbclean.py b/dbclean/dbclean.py index 4956559..274752b 100755 --- a/dbclean/dbclean.py +++ b/dbclean/dbclean.py @@ -156,6 +156,7 @@ def __str__(self): timestamp = time.strptime(filestamp, timeformat) except ValueError as e: print('%s: %s' % (file, e)) + continue if timestamp not in list(backups.keys()): backups[timestamp] = backup(timestamp, fullpath, file) From 394f03ebdd184f775216b13f09b16b5166b8cccd Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Jul 2013 20:55:01 +0200 Subject: [PATCH 10/55] add ChangeLog --- dbclean/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 dbclean/ChangeLog diff --git a/dbclean/ChangeLog b/dbclean/ChangeLog new file mode 100644 index 0000000..5b4c58c --- /dev/null +++ b/dbclean/ChangeLog @@ -0,0 +1,5 @@ +2013-07-21: +* Massive pep8 cleanup +* Update documentation (remove old --section parameter) +* Add this ChangeLog +* Add the "last" option, dbclean will always keep the given last backups. From a4c9fe0499edf58e46d0f2475544e9194c38c009 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Jul 2013 21:00:20 +0200 Subject: [PATCH 11/55] pep8 cleanup --- dbdump/dbdump.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/dbdump/dbdump.py b/dbdump/dbdump.py index 3e1a695..cdc3eab 100755 --- a/dbdump/dbdump.py +++ b/dbdump/dbdump.py @@ -22,23 +22,34 @@ along with this program. If not, see . """ -import os, sys, time, argparse, configparser -from libdump import * +import argparse +import configparser +import os +import sys +import time + +from libdump import ejabberd +from libdump import mysql +from libdump import postgresql + +def err(msg, *args): + print(msg % args, file=sys.stderr) config_file = ['/etc/dbdump/dbdump.conf', os.path.expanduser('~/.dbdump.conf')] -parser = argparse.ArgumentParser(description="Dump databases to a specified directory.") +parser = argparse.ArgumentParser( + description="Dump databases to a specified directory.") parser.add_argument('--version', action='version', version="%(prog)s 1.0") parser.add_argument('-c', '--config', action='append', default=config_file, - help="""Additional config-files to use (default: %(default)s). Can be given multiple times - to name multiple config-files.""") + help="""Additional config-files to use (default: %(default)s). Can be + given multiple times to name multiple config-files.""") parser.add_argument('--verbose', action='store_true', default=False, help="Print all called commands to stdout.") parser.add_argument('section', action='store', type=str, - help="Section in the config-file to use." ) + help="Section in the config-file to use.") args = parser.parse_args() -if args.section=='DEFAULT': +if args.section == 'DEFAULT': parser.error("--section must not be 'DEFAULT'.") config = configparser.SafeConfigParser({ @@ -52,10 +63,10 @@ # check validity of config-file: if args.section not in config: - print("Error: %s: No section found with that name." % args.section, file=sys.stderr) + err("Error: %s: No section found with that name.", args.section) sys.exit(1) if 'datadir' not in config[args.section]: - print("Error: %s: Section does not contain option 'datadir'." % args.section, file=sys.stderr) + err("Error: %s: Section does not contain option 'datadir'.", args.section) sys.exit(1) section = config[args.section] @@ -81,8 +92,8 @@ elif section['backend'] == "ejabberd": backend = ejabberd.ejabberd(section, args) else: - print("Error: %s. Unknown backend specified. Only mysql, postgresql and ejabberd are supported." - % section['backend'], file=sys.stderr) + err("Error: %s. Unknown backend specified. Only mysql, postgresql and " + "ejabberd are supported.", section['backend']) sys.exit(1) databases = backend.get_db_list() From 8c3f383c0b4322729dc89037aee0560bdbeb015b Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Jul 2013 21:01:07 +0200 Subject: [PATCH 12/55] add ChangeLog for dbdump --- dbdump/ChangeLog | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 dbdump/ChangeLog diff --git a/dbdump/ChangeLog b/dbdump/ChangeLog new file mode 100644 index 0000000..0762ccc --- /dev/null +++ b/dbdump/ChangeLog @@ -0,0 +1,3 @@ +2013-07-21: +* pep8 cleanup +* add this ChangeLog From d81e756ed5c1dfab202a3ad26d963ecaa51f7d67 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Jul 2013 21:37:46 +0200 Subject: [PATCH 13/55] update changelog --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index fb0185d..4c6d548 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +db-backup (2013-07-21-1) precise; urgency=low + + * Bump from master-branch (dbdump and dbclean now have their own changelog) + + -- Mathias Ertl Sun, 21 Jul 2013 21:36:57 +0200 + db-backup (2013-04-27-1) precise; urgency=low * Only add -E when dumping mysql table, and at correct position From 9f47cccbee0ff5adcc50d575ca054814fe84b63e Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 21 Jul 2013 21:41:29 +0200 Subject: [PATCH 14/55] update cron.d file for dbclean --- debian/changelog | 1 + debian/dbclean.cron.d | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 4c6d548..0fd9c30 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ db-backup (2013-07-21-1) precise; urgency=low * Bump from master-branch (dbdump and dbclean now have their own changelog) + * update cron.d file for dbclean -- Mathias Ertl Sun, 21 Jul 2013 21:36:57 +0200 diff --git a/debian/dbclean.cron.d b/debian/dbclean.cron.d index fb9dd43..07d3c20 100644 --- a/debian/dbclean.cron.d +++ b/debian/dbclean.cron.d @@ -1,4 +1,4 @@ -# Remove old dumps from various hosts. The parameter named with -# --section must be one found in /etc/dbclean/dbclean.conf. +# Remove old dumps from various hosts. The first argument must be a section +# found in /etc/dbclean/dbclean.conf. -#40 * * * * root dbclean --section=example.com +#40 * * * * root dbclean example.com From db88bce57366c47131d2a10630147c078472d3cb Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sat, 3 May 2014 20:19:04 +0200 Subject: [PATCH 15/55] update repository URL --- dbclean/README | 4 +++- dbdump/README | 2 +- dbdump/setup.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/dbclean/README b/dbclean/README index aef17c7..131645d 100644 --- a/dbclean/README +++ b/dbclean/README @@ -8,7 +8,9 @@ are matched to those of dbdump, so they work together. === Installation === Simply check out the git-repository: - git clone https://git.fsinf.at/fsinf/db-backup.git + + git clone https://github.com/mathiasertl/db-backup.git + If you don't want to specify the full path, you can of course copy dbclean.py somewhere in your path (/usr/local/bin is usually good). diff --git a/dbdump/README b/dbdump/README index b1188db..0f0e87a 100644 --- a/dbdump/README +++ b/dbdump/README @@ -13,7 +13,7 @@ to get it working. Simply check out the git-repository: - git clone https://git.fsinf.at/fsinf/db-backup.git + git clone https://github.com/mathiasertl/db-backup.git If you don't want to specify the full path, you can of course copy dbdump.py somewhere in your path (/usr/local/bin is usually good). Take care to copy diff --git a/dbdump/setup.py b/dbdump/setup.py index f1c29c5..8a10b5d 100644 --- a/dbdump/setup.py +++ b/dbdump/setup.py @@ -7,6 +7,6 @@ description='Database dump utilities', author='Mathias Ertl', author_email='mati@er.tl', - url='https://git.fsinf.at/fsinf/db-backup', + url='https://github.com/mathiasertl/db-backup.git', packages=['libdump'], ) From 1b166fcdeada3d4fdf7962beb9ba16da9a162a41 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 7 Dec 2014 13:33:06 +0100 Subject: [PATCH 16/55] use plain-text dumps instead of binary dumps --- dbdump/libdump/ejabberd.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dbdump/libdump/ejabberd.py b/dbdump/libdump/ejabberd.py index 777d890..597b8bb 100644 --- a/dbdump/libdump/ejabberd.py +++ b/dbdump/libdump/ejabberd.py @@ -30,7 +30,7 @@ def get_db_list(self): def get_command(self, database): path = os.path.normpath(os.path.join( - self.section['ejabberd-base-dir'], '%s.backup' % database)) + self.section['ejabberd-base-dir'], '%s.dump' % database)) return ['cat', path] def prepare_db(self, database): @@ -40,7 +40,7 @@ def prepare_db(self, database): if 'ejabberd-auth' in self.section: cmd += ['--auth', self.section['ejabberd-auth'].split()] - cmd += ['backup', database + '.backup'] + cmd += ['dump', '%sd.dump' % database] if self.args.verbose: print('%s # prepare db' % ' '.join(cmd)) p = subprocess.Popen(cmd) @@ -48,7 +48,7 @@ def prepare_db(self, database): def cleanup_db(self, database): path = os.path.normpath(os.path.join( - self.section['ejabberd-base-dir'], '%s.backup' % database)) + self.section['ejabberd-base-dir'], '%s.dump' % database)) if self.args.verbose: print('rm %s # remove local dump' % path) os.remove(path) From 1e8d9f64ac2edd1b8ff327c77b2b3eae9ce3cfb7 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 7 Dec 2014 13:35:12 +0100 Subject: [PATCH 17/55] do not redefine cmd --- dbdump/libdump/backend.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbdump/libdump/backend.py b/dbdump/libdump/backend.py index 680aee3..a0f8a68 100644 --- a/dbdump/libdump/backend.py +++ b/dbdump/libdump/backend.py @@ -79,7 +79,7 @@ def dump(self, db, timestamp): cmds.append(ssh) if self.args.verbose: - str_cmds = [' '.join(cmd) for cmd in cmds] + str_cmds = [' '.join(c) for c in cmds] print('# Dump databases:') print(' | '.join(str_cmds)) @@ -109,7 +109,7 @@ def dump(self, db, timestamp): cmds += [p2, p3, p4, p5] if self.args.verbose: - str_cmds = [' '.join(cmd) for cmd in cmds] + str_cmds = [' '.join(c) for c in cmds] print('# Dump databases:') print(' | '.join(str_cmds)) From f43e7e9b4dca01f3292de45bc297c5b06ccc7cfd Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 7 Dec 2014 13:46:34 +0100 Subject: [PATCH 18/55] rework ssh code to gzip before encryption and going over the wire, encrypted dump doesn't do anything --- dbdump/libdump/backend.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/dbdump/libdump/backend.py b/dbdump/libdump/backend.py index a0f8a68..2591013 100644 --- a/dbdump/libdump/backend.py +++ b/dbdump/libdump/backend.py @@ -68,13 +68,15 @@ def dump(self, db, timestamp): sed = ['sed', 's/-$/%s/' % os.path.basename(path)] if 'remote' in self.section: - ssh = self.get_ssh(path, [gzip, tee, sha1sum, sed]) + ssh = self.get_ssh(path, [tee, sha1sum, sed]) - cmds = [cmd] - p1 = Popen(cmd, stdout=PIPE) - p = p1 + cmds = [cmd, gzip, ] # just for output + p_dump = Popen(cmd, stdout=PIPE) + p_gzip = Popen(gzip, stdin=p_dump.stdout, stdout=PIPE) + ssh_stdin = p_gzip.stdout # what to pipe into SSH if self.gpg: - p = Popen(gpg, stdin=p1.stdout, stdout=PIPE) + p_gpg = Popen(gpg, stdin=p_gzip.stdout, stdout=PIPE) + ssh_stdin = p_gpg.stdout cmds.append(gpg) cmds.append(ssh) @@ -83,13 +85,13 @@ def dump(self, db, timestamp): print('# Dump databases:') print(' | '.join(str_cmds)) - p2 = Popen(ssh, stdin=p.stdout, stdout=PIPE) - p2.communicate() - if p2.returncode == 255: + p_ssh = Popen(ssh, stdin=ssh_stdin, stdout=PIPE) + p_ssh.communicate() + if p_ssh.returncode == 255: raise RuntimeError("SSH returned with exit code 255.") - elif p2.returncode != 0: + elif p_ssh.returncode != 0: raise RuntimeError("%s returned with exit code %s." - % (ssh, p2.returncode)) + % (ssh, p_ssh.returncode)) else: if not os.path.exists(dirname): os.mkdir(dirname, 0o700) From d210c031ed3c99ad196a5b0d4401176c03663968 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 7 Dec 2014 13:49:18 +0100 Subject: [PATCH 19/55] fix typo --- dbdump/libdump/ejabberd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbdump/libdump/ejabberd.py b/dbdump/libdump/ejabberd.py index 597b8bb..f5826cf 100644 --- a/dbdump/libdump/ejabberd.py +++ b/dbdump/libdump/ejabberd.py @@ -40,7 +40,7 @@ def prepare_db(self, database): if 'ejabberd-auth' in self.section: cmd += ['--auth', self.section['ejabberd-auth'].split()] - cmd += ['dump', '%sd.dump' % database] + cmd += ['dump', '%s.dump' % database] if self.args.verbose: print('%s # prepare db' % ' '.join(cmd)) p = subprocess.Popen(cmd) From fe8038f221a0da42d502f0fccd55d283e7e35d29 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 7 Dec 2014 13:57:29 +0100 Subject: [PATCH 20/55] add .gz before .gpg, use os.path.join --- dbdump/libdump/backend.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dbdump/libdump/backend.py b/dbdump/libdump/backend.py index 2591013..3e65d1f 100644 --- a/dbdump/libdump/backend.py +++ b/dbdump/libdump/backend.py @@ -50,8 +50,8 @@ def dump(self, db, timestamp): if not cmd: return - dirname = os.path.normpath(self.base + '/' + db) - path = os.path.normpath(dirname + '/' + timestamp) + dirname = os.path.join(self.base, db) + path = os.path.join(dirname, '%s.gz' % timestamp) if self.gpg: gpg = ['gpg'] if 'sign_key' in self.section: @@ -60,8 +60,6 @@ def dump(self, db, timestamp): gpg += ['-e', '-r', self.section['recipient']] path += '.gpg' - path += '.gz' - gzip = ['gzip', '-f', '-9', '-', '-'] tee = ['tee', path] sha1sum = ['sha1sum'] From 97cdf8c534d0960555bc81f816e89658a9f9f201 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 7 Dec 2014 13:59:14 +0100 Subject: [PATCH 21/55] call abspath --- dbdump/libdump/backend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbdump/libdump/backend.py b/dbdump/libdump/backend.py index 3e65d1f..56b7279 100644 --- a/dbdump/libdump/backend.py +++ b/dbdump/libdump/backend.py @@ -50,7 +50,7 @@ def dump(self, db, timestamp): if not cmd: return - dirname = os.path.join(self.base, db) + dirname = os.path.abspath(os.path.join(self.base, db)) path = os.path.join(dirname, '%s.gz' % timestamp) if self.gpg: gpg = ['gpg'] From c996effa84af0f218928cf28340fd2b40f3158b5 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 7 Dec 2014 14:08:42 +0100 Subject: [PATCH 22/55] rework local part to compress first --- dbdump/libdump/backend.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/dbdump/libdump/backend.py b/dbdump/libdump/backend.py index 56b7279..f096f7a 100644 --- a/dbdump/libdump/backend.py +++ b/dbdump/libdump/backend.py @@ -95,25 +95,26 @@ def dump(self, db, timestamp): os.mkdir(dirname, 0o700) f = open(path + '.sha1', 'w') - cmds = [cmd] - p1 = Popen(cmd, stdout=PIPE) - p = p1 + cmds = [cmd, gzip, ] # just for output + p_dump = Popen(cmd, stdout=PIPE) + p_gzip = Popen(gzip, stdin=p_dump.stdout, stdout=PIPE) + tee_pipe = p_gzip.stdout if self.gpg: - p = Popen(gpg, stdin=p1.stdout, stdout=PIPE) + p_gpg = Popen(gpg, stdin=p_dump.stdout, stdout=PIPE) + tee_pipe = p_gpg.stdout cmds.append(gpg) - p2 = Popen(gzip, stdin=p1.stdout, stdout=PIPE) - p3 = Popen(tee, stdin=p2.stdout, stdout=PIPE) - p4 = Popen(sha1sum, stdin=p3.stdout, stdout=PIPE) - p5 = Popen(sed, stdin=p4.stdout, stdout=f) + p_tee = Popen(tee, stdin=tee_pipe, stdout=PIPE) + p_sha1 = Popen(sha1sum, stdin=p_tee.stdout, stdout=PIPE) + p_sed = Popen(sed, stdin=p_sha1.stdout, stdout=f) - cmds += [p2, p3, p4, p5] + cmds += [tee, sha1sum, sed] if self.args.verbose: str_cmds = [' '.join(c) for c in cmds] print('# Dump databases:') print(' | '.join(str_cmds)) - p5.communicate() + p_sed.communicate() f.close() def prepare(self): From e54d9b684018b16a8c19cd8b24017bee46cf5382 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 7 Dec 2014 14:22:20 +0100 Subject: [PATCH 23/55] update changelog, control --- debian/changelog | 9 +++++++++ debian/control | 8 ++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/debian/changelog b/debian/changelog index 0fd9c30..594774e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +db-backup (2014-12-09-1) unstable; urgency=low + + * Create text-dumps for ejabberd. + * Compress dumps before encrypting them for better compression results. + * Update maintainer address. + * Increase debhelper dependency, update VCS-* fields. + + -- Mathias Ertl Sun, 07 Dec 2014 14:20:37 +0100 + db-backup (2013-07-21-1) precise; urgency=low * Bump from master-branch (dbdump and dbclean now have their own changelog) diff --git a/debian/control b/debian/control index 204b187..e2f5087 100644 --- a/debian/control +++ b/debian/control @@ -1,11 +1,11 @@ Source: db-backup Section: net Priority: optional -Maintainer: Mathias Ertl +Maintainer: Mathias Ertl Standards-Version: 3.9.2 -Build-Depends: debhelper (>= 7.0.50~), python3-all -Vcs-Browser: http://git.fsinf.at/fsinf/db-backup -Vcs-Git: http://git.fsinf.at/fsinf/db-backup.git +Build-Depends: debhelper (>= 9), python3-all +Vcs-Browser: https://github.com/mathiasertl/db-backup +Vcs-Git: https://github.com/mathiasertl/db-backup.git Package: dbdump Architecture: all From 9df869027b73cb04897d5cae370edbe828fc35e3 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 7 Dec 2014 14:22:55 +0100 Subject: [PATCH 24/55] increase compat --- debian/compat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/compat b/debian/compat index 7f8f011..ec63514 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -7 +9 From cc1de22161c690f16d42f51698e4c9fada41a8d5 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 7 Dec 2014 14:24:01 +0100 Subject: [PATCH 25/55] update copyright file --- debian/changelog | 1 + debian/copyright | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/debian/changelog b/debian/changelog index 594774e..4a3ec38 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,7 @@ db-backup (2014-12-09-1) unstable; urgency=low * Compress dumps before encrypting them for better compression results. * Update maintainer address. * Increase debhelper dependency, update VCS-* fields. + * Update copyright file to up-to-date format. -- Mathias Ertl Sun, 07 Dec 2014 14:20:37 +0100 diff --git a/debian/copyright b/debian/copyright index 8845b03..1044b76 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,7 +1,7 @@ -Format: http://anonscm.debian.org/viewvc/dep/web/deps/dep5.mdwn?revision=173&view=markup -Upstream-Name: fw-rules -Upstream-Contact: Mathias Ertl -Source: https://git.fsinf.at/fsinf/fw-rules +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: db-backup +Upstream-Contact: Mathias Ertl +Source: https://github.com/mathiasertl/db-backup Files: * Copyright: Copyright (c) 2011, Mathias Ertl From 9d00475f96a64e6f56004a379c791e938f666fd2 Mon Sep 17 00:00:00 2001 From: David Kaufmann Date: Thu, 12 Feb 2015 22:36:23 +0100 Subject: [PATCH 26/55] execute commands as database users in a login shell --- dbdump/libdump/backend.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbdump/libdump/backend.py b/dbdump/libdump/backend.py index f096f7a..af0b99e 100644 --- a/dbdump/libdump/backend.py +++ b/dbdump/libdump/backend.py @@ -33,7 +33,7 @@ def __init__(self, section, args): def make_su(self, cmd): if 'su' in self.section: - cmd = ['su', self.section['su'], '-s', + cmd = ['su', '-', self.section['su'], '-s', '/bin/bash', '-c', ' '.join(cmd)] return cmd From 2e374f9e0b16111f341f9851aaa44ec8a056175b Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 14 Feb 2016 14:13:10 +0100 Subject: [PATCH 27/55] fix --version parameter --- dbclean/ChangeLog | 3 +++ dbclean/dbclean.py | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dbclean/ChangeLog b/dbclean/ChangeLog index 5b4c58c..9a4087c 100644 --- a/dbclean/ChangeLog +++ b/dbclean/ChangeLog @@ -1,3 +1,6 @@ +2016-02-14: +* Fix --version parameter. + 2013-07-21: * Massive pep8 cleanup * Update documentation (remove old --section parameter) diff --git a/dbclean/dbclean.py b/dbclean/dbclean.py index 274752b..9ba3b68 100755 --- a/dbclean/dbclean.py +++ b/dbclean/dbclean.py @@ -41,9 +41,10 @@ def err(msg, *args): os.path.expanduser('~/.dbclean.conf') ] -parser = argparse.ArgumentParser(version="%prog 1.0", +parser = argparse.ArgumentParser( description="""Cleanup regular database dumps created by dbdump. This script keeps backups at given intervals for a given amount of time.""") +parser.add_argument('--version', action='version', version='%(prog)s 1.1') parser.add_argument( '-c', '--config', type=str, dest='config', action='append', default=config_file, help="""Additional config-files to use (default: From 098fdea6d28aa336558704a39d1dea4656fb01df Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 14 Feb 2016 14:17:29 +0100 Subject: [PATCH 28/55] use tw=99 --- .pep8 | 2 ++ dbclean/ChangeLog | 1 + dbclean/dbclean.py | 57 ++++++++++++++++++++-------------------------- 3 files changed, 28 insertions(+), 32 deletions(-) create mode 100644 .pep8 diff --git a/.pep8 b/.pep8 new file mode 100644 index 0000000..c1b094e --- /dev/null +++ b/.pep8 @@ -0,0 +1,2 @@ +[pep8] +max-line-length = 99 diff --git a/dbclean/ChangeLog b/dbclean/ChangeLog index 9a4087c..25d7878 100644 --- a/dbclean/ChangeLog +++ b/dbclean/ChangeLog @@ -1,5 +1,6 @@ 2016-02-14: * Fix --version parameter. +* Use a text-width of 99 chars. 2013-07-21: * Massive pep8 cleanup diff --git a/dbclean/dbclean.py b/dbclean/dbclean.py index 9ba3b68..82e52be 100755 --- a/dbclean/dbclean.py +++ b/dbclean/dbclean.py @@ -1,29 +1,24 @@ #!/usr/bin/env python3 - -""" -This program is designed to clean files from a specified directory. -The program is designed to work together with dbdump.py, so it is -basically designed to clean out regular database dumps. The files -are kept at a certain granularity (so daily backups will be kept -for a month, monthly backups for a year, etc. -Please see the README file for how to use this script and supported -features. You might also try calling this program with '--help'. - -Copyright 2009 - 2013 Mathias Ertl - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -""" +# -*- coding: utf-8 -*- +# +# This program is designed to clean files from a specified directory. The program is designed to +# work together with dbdump.py, so it is basically designed to clean out regular database dumps. +# The files are kept at a certain granularity (so daily backups will be kept for a month, monthly +# backups for a year, etc. Please see the README file for how to use this script and supported +# features. You might also try calling this program with '--help'. +# +# Copyright 2009 - 2016 Mathias Ertl +# +# This program is free software: you can redistribute it and/or modify it under the terms of the +# GNU General Public License as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . import argparse import calendar @@ -42,16 +37,14 @@ def err(msg, *args): ] parser = argparse.ArgumentParser( - description="""Cleanup regular database dumps created by dbdump. This -script keeps backups at given intervals for a given amount of time.""") + description="""Cleanup regular database dumps created by dbdump. This script keeps backups at +given intervals for a given amount of time.""") parser.add_argument('--version', action='version', version='%(prog)s 1.1') parser.add_argument( '-c', '--config', type=str, dest='config', action='append', - default=config_file, help="""Additional config-files to use (default: - %(default)s). Can be given multiple times to name multiple - config-files.""") -parser.add_argument('section', action='store', type=str, - help="Section in the config-file to use.") + default=config_file, help="""Additional config-files to use (default: %(default)s). Can be + given multiple times to name multiple config-files.""") +parser.add_argument('section', action='store', type=str, help="Section in the config-file to use.") args = parser.parse_args() if args.section == 'DEFAULT': From 9b869b17dc80cbd9c65da685deef24fec3f7d6e4 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 14 Feb 2016 14:21:54 +0100 Subject: [PATCH 29/55] tw=99 --- dbdump/dbdump.py | 61 +++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/dbdump/dbdump.py b/dbdump/dbdump.py index cdc3eab..afab2f6 100755 --- a/dbdump/dbdump.py +++ b/dbdump/dbdump.py @@ -1,26 +1,22 @@ #!/usr/bin/env python3 - -""" -This program is designed to regulary dump SQL databases into a -specified directory for backup purposes. Please see the README file -for how to use this script and supported features. You might also -try calling this program with '--help'. - -Copyright 2009-2012 Mathias Ertl - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -""" +# -*- coding: utf-8 -*- +# +# This program is designed to regulary dump SQL databases into a specified directory for backup +# purposes. Please see the README file for how to use this script and supported features. You might +# also try calling this program with '--help'. +# +# Copyright 2009-2016 Mathias Ertl +# +# This program is free software: you can redistribute it and/or modify it under the terms of the +# GNU General Public License as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with this program. If +# not, see . import argparse import configparser @@ -32,21 +28,22 @@ from libdump import mysql from libdump import postgresql + def err(msg, *args): print(msg % args, file=sys.stderr) config_file = ['/etc/dbdump/dbdump.conf', os.path.expanduser('~/.dbdump.conf')] -parser = argparse.ArgumentParser( - description="Dump databases to a specified directory.") -parser.add_argument('--version', action='version', version="%(prog)s 1.0") -parser.add_argument('-c', '--config', action='append', default=config_file, - help="""Additional config-files to use (default: %(default)s). Can be - given multiple times to name multiple config-files.""") +parser = argparse.ArgumentParser(description="Dump databases to a specified directory.") +parser.add_argument('--version', action='version', version="%(prog)s 1.1") +parser.add_argument( + '-c', '--config', action='append', default=config_file, + help="""Additional config-files to use (default: %(default)s). Can be given multiple times to + name multiple config-files.""") parser.add_argument('--verbose', action='store_true', default=False, - help="Print all called commands to stdout.") + help="Print all called commands to stdout.") parser.add_argument('section', action='store', type=str, - help="Section in the config-file to use.") + help="Section in the config-file to use.") args = parser.parse_args() if args.section == 'DEFAULT': @@ -92,8 +89,8 @@ def err(msg, *args): elif section['backend'] == "ejabberd": backend = ejabberd.ejabberd(section, args) else: - err("Error: %s. Unknown backend specified. Only mysql, postgresql and " - "ejabberd are supported.", section['backend']) + err("Error: %s. Unknown backend specified. Only mysql, postgresql and ejabberd are supported.", + section['backend']) sys.exit(1) databases = backend.get_db_list() From 90a436f48fe8aef2bba30d100a835e29720556d5 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Fri, 12 Aug 2016 14:23:07 +0200 Subject: [PATCH 30/55] cosmetics --- dbdump/libdump/ejabberd.py | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/dbdump/libdump/ejabberd.py b/dbdump/libdump/ejabberd.py index f5826cf..779aaac 100644 --- a/dbdump/libdump/ejabberd.py +++ b/dbdump/libdump/ejabberd.py @@ -1,22 +1,19 @@ -""" -This file is part of dbdump. - -Copyright 2009-2012 Mathias Ertl - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -""" - +# -*- coding: utf-8 -*- +# +# This file is part of dbdump. +# +# Copyright 2009-2016 Mathias Ertl +# +# This program is free software: you can redistribute it and/or modify it under the terms of the +# GNU General Public License as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with this program. If +# not, see . import os import subprocess From 103864277f463a8f13e2d997c7fe697dc7f0942e Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 20 Jan 2019 13:52:22 +0100 Subject: [PATCH 31/55] add pyenv version --- .python-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .python-version diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..4f2c1d1 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.6.6 From d42544edccc3b6d47211522fda98bcf2e78b12eb Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 20 Jan 2019 13:52:31 +0100 Subject: [PATCH 32/55] fix spaces --- dbdump/libdump/ejabberd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dbdump/libdump/ejabberd.py b/dbdump/libdump/ejabberd.py index 779aaac..32bd581 100644 --- a/dbdump/libdump/ejabberd.py +++ b/dbdump/libdump/ejabberd.py @@ -9,10 +9,10 @@ # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # -# You should have received a copy of the GNU General Public License along with this program. If +# You should have received a copy of the GNU General Public License along with this program. If # not, see . import os From 1bf43016c1e4dd519dbc31d8b903623cf6a09618 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 20 Jan 2019 13:53:13 +0100 Subject: [PATCH 33/55] add dev reqs --- requirements-dev.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 requirements-dev.txt diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..df6fd48 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,2 @@ +flake8==3.6.0 +isort==4.3.4 From fc434369205f1fc88f144997981c15b7f9cba6ba Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 20 Jan 2019 13:55:36 +0100 Subject: [PATCH 34/55] add tox.ini --- tox.ini | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tox.ini diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..099c81c --- /dev/null +++ b/tox.ini @@ -0,0 +1,17 @@ +[tox] +# https://devguide.python.org/#status-of-python-branches +envlist = py{35,36,37} + +[testenv] +deps = + -rrequirements-dev.txt +commands = + flake8 dbdump dbclean + isort --check-only --diff -rc dbdump dbclean + +[flake8] +max-line-length = 110 +ignore = E265 + +[isort] +force_single_line = true From 04aa873043ce49bc753f3dd5b0eebb7c789e424f Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 20 Jan 2019 14:03:17 +0100 Subject: [PATCH 35/55] udpate style, unify header --- dbclean/dbclean.py | 6 +++--- dbdump/dbdump.py | 4 ++-- dbdump/libdump/__init__.py | 30 ++++++++++++------------------ dbdump/libdump/backend.py | 30 ++++++++++++------------------ dbdump/libdump/ejabberd.py | 16 ++++++---------- dbdump/libdump/mysql.py | 35 +++++++++++++++-------------------- dbdump/libdump/postgresql.py | 34 ++++++++++++++-------------------- dbdump/setup.py | 17 +++++++++-------- 8 files changed, 73 insertions(+), 99 deletions(-) diff --git a/dbclean/dbclean.py b/dbclean/dbclean.py index 82e52be..396e145 100755 --- a/dbclean/dbclean.py +++ b/dbclean/dbclean.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- # # This program is designed to clean files from a specified directory. The program is designed to # work together with dbdump.py, so it is basically designed to clean out regular database dumps. @@ -7,7 +6,7 @@ # backups for a year, etc. Please see the README file for how to use this script and supported # features. You might also try calling this program with '--help'. # -# Copyright 2009 - 2016 Mathias Ertl +# Copyright 2009 - 2019 Mathias Ertl # # This program is free software: you can redistribute it and/or modify it under the terms of the # GNU General Public License as published by the Free Software Foundation, either version 3 of the @@ -31,6 +30,7 @@ def err(msg, *args): print(msg % args, file=sys.stderr) + config_file = [ '/etc/dbclean/dbclean.conf', os.path.expanduser('~/.dbclean.conf') @@ -84,6 +84,7 @@ def err(msg, *args): monthly = int(config[args.section]['monthly']) yearly = int(config[args.section]['yearly']) last = int(config[args.section]['last']) +now = time.time() class backup(): @@ -122,7 +123,6 @@ def remove(self): def __str__(self): return "%s in %s" % (self.files, self.base) -now = time.time() # loop through each dir in datadir for dir in os.listdir(datadir): diff --git a/dbdump/dbdump.py b/dbdump/dbdump.py index afab2f6..8038b0d 100755 --- a/dbdump/dbdump.py +++ b/dbdump/dbdump.py @@ -1,11 +1,10 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- # # This program is designed to regulary dump SQL databases into a specified directory for backup # purposes. Please see the README file for how to use this script and supported features. You might # also try calling this program with '--help'. # -# Copyright 2009-2016 Mathias Ertl +# Copyright 2009-2019 Mathias Ertl # # This program is free software: you can redistribute it and/or modify it under the terms of the # GNU General Public License as published by the Free Software Foundation, either version 3 of the @@ -32,6 +31,7 @@ def err(msg, *args): print(msg % args, file=sys.stderr) + config_file = ['/etc/dbdump/dbdump.conf', os.path.expanduser('~/.dbdump.conf')] parser = argparse.ArgumentParser(description="Dump databases to a specified directory.") diff --git a/dbdump/libdump/__init__.py b/dbdump/libdump/__init__.py index 4704b2f..dcbd346 100644 --- a/dbdump/libdump/__init__.py +++ b/dbdump/libdump/__init__.py @@ -1,20 +1,14 @@ -""" -This file is part of dbdump. - -Copyright 2009-2012 Mathias Ertl - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -""" +# This file is part of dbdump (https://github.com/mathiasertl/db-backup). +# +# dbdump is free software: you can redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# dbdump is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with dbdump. If not, +# see . __all__ = ['backend', 'mysql', 'postgresql', 'ejabberd'] diff --git a/dbdump/libdump/backend.py b/dbdump/libdump/backend.py index f096f7a..eda8d3d 100644 --- a/dbdump/libdump/backend.py +++ b/dbdump/libdump/backend.py @@ -1,21 +1,15 @@ -""" -This file is part of dbdump. - -Copyright 2009, 2010 Mathias Ertl - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -""" +# This file is part of dbdump (https://github.com/mathiasertl/db-backup). +# +# dbdump is free software: you can redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# dbdump is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with dbdump. If not, +# see . import os from subprocess import Popen, PIPE diff --git a/dbdump/libdump/ejabberd.py b/dbdump/libdump/ejabberd.py index 32bd581..6d1721c 100644 --- a/dbdump/libdump/ejabberd.py +++ b/dbdump/libdump/ejabberd.py @@ -1,19 +1,15 @@ -# -*- coding: utf-8 -*- +# This file is part of dbdump (https://github.com/mathiasertl/db-backup). # -# This file is part of dbdump. -# -# Copyright 2009-2016 Mathias Ertl -# -# This program is free software: you can redistribute it and/or modify it under the terms of the -# GNU General Public License as published by the Free Software Foundation, either version 3 of the +# dbdump is free software: you can redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # -# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# dbdump is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # -# You should have received a copy of the GNU General Public License along with this program. If -# not, see . +# You should have received a copy of the GNU General Public License along with dbdump. If not, +# see . import os import subprocess diff --git a/dbdump/libdump/mysql.py b/dbdump/libdump/mysql.py index 4105845..b47e636 100644 --- a/dbdump/libdump/mysql.py +++ b/dbdump/libdump/mysql.py @@ -1,27 +1,22 @@ -""" -This file is part of dbdump. - -Copyright 2009-2012 Mathias Ertl - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -""" +# This file is part of dbdump (https://github.com/mathiasertl/db-backup). +# +# dbdump is free software: you can redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# dbdump is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with dbdump. If not, +# see . import os import stat import sys -from subprocess import * +from subprocess import Popen +from subprocess import PIPE from libdump import backend @@ -63,7 +58,7 @@ def get_db_list(self): if p_list.returncode != 0: raise Exception("Unable to get list of databases: %s " - % (stderr.decode().strip("\n"))) + % (stderr.decode().strip("\n"))) return [db for db in databases if db not in excluded] diff --git a/dbdump/libdump/postgresql.py b/dbdump/libdump/postgresql.py index c2f51a7..a3a93c0 100644 --- a/dbdump/libdump/postgresql.py +++ b/dbdump/libdump/postgresql.py @@ -1,21 +1,15 @@ -""" -This file is part of dbdump. - -Copyright 2009-2012 Mathias Ertl - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -""" +# This file is part of dbdump (https://github.com/mathiasertl/db-backup). +# +# dbdump is free software: you can redistribute it and/or modify it under the terms of the GNU +# General Public License as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# dbdump is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with dbdump. If not, +# see . from subprocess import Popen, PIPE @@ -31,7 +25,7 @@ def get_db_list(self): if 'su' in self.section: cmd = ['su', self.section['su'], '-s', '/bin/bash', '-c', - ' '.join(cmd)] + ' '.join(cmd)] p_list = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = p_list.communicate() @@ -41,7 +35,7 @@ def get_db_list(self): p_list.wait() if p_list.returncode != 0: raise Exception("Unable to get list of databases: %s " - % (stderr.decode().strip("\n"))) + % (stderr.decode().strip("\n"))) return databases diff --git a/dbdump/setup.py b/dbdump/setup.py index 8a10b5d..b6a1198 100644 --- a/dbdump/setup.py +++ b/dbdump/setup.py @@ -2,11 +2,12 @@ from distutils.core import setup -setup(name='dbdump', - version='1.0', - description='Database dump utilities', - author='Mathias Ertl', - author_email='mati@er.tl', - url='https://github.com/mathiasertl/db-backup.git', - packages=['libdump'], - ) +setup( + name='dbdump', + version='1.0', + description='Database dump utilities', + author='Mathias Ertl', + author_email='mati@er.tl', + url='https://github.com/mathiasertl/db-backup.git', + packages=['libdump'], +) From 8a81250ba3a42cc4002b951290b0f7a58ef6fd6b Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 20 Jan 2019 14:21:45 +0100 Subject: [PATCH 36/55] various style improvs --- dbdump/ChangeLog | 4 ++++ dbdump/dbdump.conf.example | 42 ++++++++++++++++++++++---------------- dbdump/dbdump.py | 2 ++ dbdump/libdump/backend.py | 17 ++++++++++++--- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/dbdump/ChangeLog b/dbdump/ChangeLog index 0762ccc..fadb438 100644 --- a/dbdump/ChangeLog +++ b/dbdump/ChangeLog @@ -1,3 +1,7 @@ +# 1.2 +* flake8/isort cleanup +* Add new options: ssh-timeout and ssh-options + 2013-07-21: * pep8 cleanup * add this ChangeLog diff --git a/dbdump/dbdump.conf.example b/dbdump/dbdump.conf.example index e9d56a0..71bb318 100644 --- a/dbdump/dbdump.conf.example +++ b/dbdump/dbdump.conf.example @@ -11,74 +11,80 @@ # Note that the default is the section name, if you do not explicitly set # this in this file. #backend=mysql -# + # The base directory to dump your databases to. # Default is /var/backups/ #datadir=/var/backups/mysql -# + # Use su to drop privileges to the specified user for all SQL related # commands (optional): #su=mysql -# + # Store dumps on a remote location via SSH. REMOTE will be passed to ssh # unchanged (optional): remote = user@backup.example.com -# + +# Override the default ssh connect-timeout of 10 seconds: +#ssh-timeout = 10 + +# Space-separated list of any other SSH options to pass to ssh, for example: +#ssh-options = -o Compression=yes -v + # Sign and/or encrypt backups using the specified GPG keys (optional): #sign-key = dbdump@hostname.example.net #recipient = admin@hostname.example.net -# + # You can also use the interpolation feature provided by the # ConfigParser python module. -# + # You can even specify new settings to use in later interpolation: #hostname = example.com -# + # We set the default datadir using dynamic interpolation: #datadir = /var/backups/%(hostname)s/%(backend)s/ -# + #[mysql] # Dump MySQL databases. Because of the settings in the DEFAULT section, # the backend used here is 'mysql' and datadir evaluates to: # /var/backups/example.com/mysql/ # ... and backups will be signed and encrypted (see first lines in the # DEFAULT section). -# + # MYSQL OPTIONS: # # Use a custom defaults-file. This file should be used to specify access # credentials (default given here): #mysql-defaults = ~/.my.cnf -# + # Ignore given tables when dumping. This can be useful if a certain # table does not use InnoDB and the database could not be dumped in a # single transaction otherwise (optional): #mysql-ignore-tables = db_foo.table_bla db_bar.table_hugo -# + #[postgresql] # Dump PostgreSQL databases. -# + # lets override the default datadir, just to be clear: #datadir=/somewhere/else/ -# + # POSTGRESQL OPTIONS: -# + # Additional command-line parameters for psql and pgdump (optional): #postgresql-psql-opts = --someopt #postgresql-pgdump-opts = --otheropt -# + #[ejabberd] # Dump ejabberd databases. -# + # EJABBERD OPTIONS: # # Dump database from this ejabberd node (optional): #ejabberd-node = ejabberd -# + # Authenticate with the erlang node. This specifies a normal account on # the jabber server (optional): #ejabberd-auth = user jabber.example.com password -# + # Base directory where the ejabberd database is stored (default given # here): #ejabberd-base-dir = /var/lib/ejabberd diff --git a/dbdump/dbdump.py b/dbdump/dbdump.py index 8038b0d..31d86ea 100755 --- a/dbdump/dbdump.py +++ b/dbdump/dbdump.py @@ -54,6 +54,8 @@ def err(msg, *args): 'datadir': '/var/backups/%(backend)s', 'mysql-ignore-tables': '', 'ejabberd-base-dir': '/var/lib/ejabberd', + 'ssh-timeout': '10', + 'ssh-options': '', }) if not config.read(args.config): parser.error("No config-files could be read.") diff --git a/dbdump/libdump/backend.py b/dbdump/libdump/backend.py index eda8d3d..b6590d3 100644 --- a/dbdump/libdump/backend.py +++ b/dbdump/libdump/backend.py @@ -11,6 +11,7 @@ # You should have received a copy of the GNU General Public License along with dbdump. If not, # see . +import shlex import os from subprocess import Popen, PIPE @@ -33,11 +34,21 @@ def make_su(self, cmd): def get_ssh(self, path, cmds): cmds = [' '.join(cmd) for cmd in cmds] - opts = self.section['remote'].split() prefix = 'umask 077; mkdir -m 0700 -p %s; ' % os.path.dirname(path) ssh_cmd = prefix + ' | '.join(cmds) + ' > %s.sha1' % path - test = ['ssh'] + opts + [ssh_cmd] - return test + + ssh = ['ssh'] + timeout = self.section['ssh-timeout'] + if timeout: + ssh += ['-o', 'ConnectTimeout=%s' % timeout, ] + + opts = self.section['ssh-options'] + if opts: + ssh += shlex.split(opts) + + ssh += [self.section['remote'], ssh_cmd] + + return ssh def dump(self, db, timestamp): cmd = self.make_su(self.get_command(db)) From f1711c3ea91bb4e59b6621796e79e22b72aa940b Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 20 Jan 2019 14:23:17 +0100 Subject: [PATCH 37/55] switch to sha256 checksums --- dbdump/ChangeLog | 1 + dbdump/libdump/backend.py | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/dbdump/ChangeLog b/dbdump/ChangeLog index fadb438..6b06bc6 100644 --- a/dbdump/ChangeLog +++ b/dbdump/ChangeLog @@ -1,6 +1,7 @@ # 1.2 * flake8/isort cleanup * Add new options: ssh-timeout and ssh-options +* Switch to generating sha256 checksums 2013-07-21: * pep8 cleanup diff --git a/dbdump/libdump/backend.py b/dbdump/libdump/backend.py index b6590d3..7e34908 100644 --- a/dbdump/libdump/backend.py +++ b/dbdump/libdump/backend.py @@ -35,7 +35,7 @@ def make_su(self, cmd): def get_ssh(self, path, cmds): cmds = [' '.join(cmd) for cmd in cmds] prefix = 'umask 077; mkdir -m 0700 -p %s; ' % os.path.dirname(path) - ssh_cmd = prefix + ' | '.join(cmds) + ' > %s.sha1' % path + ssh_cmd = prefix + ' | '.join(cmds) + ' > %s.sha256' % path ssh = ['ssh'] timeout = self.section['ssh-timeout'] @@ -67,11 +67,11 @@ def dump(self, db, timestamp): gzip = ['gzip', '-f', '-9', '-', '-'] tee = ['tee', path] - sha1sum = ['sha1sum'] + sha = ['sha256sum'] sed = ['sed', 's/-$/%s/' % os.path.basename(path)] if 'remote' in self.section: - ssh = self.get_ssh(path, [tee, sha1sum, sed]) + ssh = self.get_ssh(path, [tee, sha, sed]) cmds = [cmd, gzip, ] # just for output p_dump = Popen(cmd, stdout=PIPE) @@ -99,7 +99,7 @@ def dump(self, db, timestamp): if not os.path.exists(dirname): os.mkdir(dirname, 0o700) - f = open(path + '.sha1', 'w') + f = open(path + '.sha256', 'w') cmds = [cmd, gzip, ] # just for output p_dump = Popen(cmd, stdout=PIPE) p_gzip = Popen(gzip, stdin=p_dump.stdout, stdout=PIPE) @@ -110,10 +110,10 @@ def dump(self, db, timestamp): cmds.append(gpg) p_tee = Popen(tee, stdin=tee_pipe, stdout=PIPE) - p_sha1 = Popen(sha1sum, stdin=p_tee.stdout, stdout=PIPE) - p_sed = Popen(sed, stdin=p_sha1.stdout, stdout=f) + p_sha = Popen(sha, stdin=p_tee.stdout, stdout=PIPE) + p_sed = Popen(sed, stdin=p_sha.stdout, stdout=f) - cmds += [tee, sha1sum, sed] + cmds += [tee, sha, sed] if self.args.verbose: str_cmds = [' '.join(c) for c in cmds] print('# Dump databases:') From c40a9213927962205847c12426a7f1b211d728cc Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 20 Jan 2019 14:25:36 +0100 Subject: [PATCH 38/55] minor style --- dbdump/libdump/backend.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dbdump/libdump/backend.py b/dbdump/libdump/backend.py index 7e34908..f49cd18 100644 --- a/dbdump/libdump/backend.py +++ b/dbdump/libdump/backend.py @@ -16,7 +16,7 @@ from subprocess import Popen, PIPE -class backend(object): +class backend: def __init__(self, section, args): self.args = args self.section = section @@ -93,8 +93,7 @@ def dump(self, db, timestamp): if p_ssh.returncode == 255: raise RuntimeError("SSH returned with exit code 255.") elif p_ssh.returncode != 0: - raise RuntimeError("%s returned with exit code %s." - % (ssh, p_ssh.returncode)) + raise RuntimeError("%s returned with exit code %s." % (ssh, p_ssh.returncode)) else: if not os.path.exists(dirname): os.mkdir(dirname, 0o700) From 2fd0c110390048ba523ec5cc132a009ff50bb518 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Sun, 20 Jan 2019 14:26:53 +0100 Subject: [PATCH 39/55] isort cleanup --- dbdump/libdump/backend.py | 5 +++-- dbdump/libdump/mysql.py | 3 +-- dbdump/libdump/postgresql.py | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/dbdump/libdump/backend.py b/dbdump/libdump/backend.py index f49cd18..9bb2151 100644 --- a/dbdump/libdump/backend.py +++ b/dbdump/libdump/backend.py @@ -11,9 +11,10 @@ # You should have received a copy of the GNU General Public License along with dbdump. If not, # see . -import shlex import os -from subprocess import Popen, PIPE +import shlex +from subprocess import PIPE +from subprocess import Popen class backend: diff --git a/dbdump/libdump/mysql.py b/dbdump/libdump/mysql.py index b47e636..50b3e83 100644 --- a/dbdump/libdump/mysql.py +++ b/dbdump/libdump/mysql.py @@ -14,9 +14,8 @@ import os import stat import sys - -from subprocess import Popen from subprocess import PIPE +from subprocess import Popen from libdump import backend diff --git a/dbdump/libdump/postgresql.py b/dbdump/libdump/postgresql.py index a3a93c0..af2d08d 100644 --- a/dbdump/libdump/postgresql.py +++ b/dbdump/libdump/postgresql.py @@ -11,7 +11,8 @@ # You should have received a copy of the GNU General Public License along with dbdump. If not, # see . -from subprocess import Popen, PIPE +from subprocess import PIPE +from subprocess import Popen from libdump import backend From aa1736daa1f3c0e7208fd637dbe6fcbd6cc7707d Mon Sep 17 00:00:00 2001 From: somenet Date: Tue, 16 Jul 2019 15:27:14 +0200 Subject: [PATCH 40/55] Update dbdump.py Silence: ``/usr/bin/dbdump:59: DeprecationWarning: The SafeConfigParser class has been renamed to ConfigParser in Python 3.2. This alias will be removed in future versions. Use ConfigParser directly instead.`` --- dbdump/dbdump.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbdump/dbdump.py b/dbdump/dbdump.py index 31d86ea..e593681 100755 --- a/dbdump/dbdump.py +++ b/dbdump/dbdump.py @@ -49,7 +49,7 @@ def err(msg, *args): if args.section == 'DEFAULT': parser.error("--section must not be 'DEFAULT'.") -config = configparser.SafeConfigParser({ +config = configparser.ConfigParser({ 'format': '%%Y-%%m-%%d_%%H:%%M:%%S', 'datadir': '/var/backups/%(backend)s', 'mysql-ignore-tables': '', From f1f8df26d89c413a7bc77bb967daf276e2722ffe Mon Sep 17 00:00:00 2001 From: David Kaufmann Date: Sat, 20 Jul 2019 17:36:06 +0200 Subject: [PATCH 41/55] update changelog --- debian/changelog | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/debian/changelog b/debian/changelog index 4a3ec38..8902d02 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,28 @@ +db-backup (2019-07-20-1) unstable; urgency=low + + [ David Kaufmann ] + * execute commands as database users in a login shell + + [ Mathias Ertl ] + * fix --version parameter + * use tw=99 + * tw=99 + * cosmetics + * add pyenv version + * fix spaces + * add dev reqs + * add tox.ini + * udpate style, unify header + * various style improvs + * switch to sha256 checksums + * minor style + * isort cleanup + + [ somenet ] + * Update dbdump.py + + -- David Kaufmann Sat, 20 Jul 2019 17:32:00 +0200 + db-backup (2014-12-09-1) unstable; urgency=low * Create text-dumps for ejabberd. From 16da19ba8352bacefdb30e2d32dfab7fbb8cfba5 Mon Sep 17 00:00:00 2001 From: David Kaufmann Date: Sat, 20 Jul 2019 17:57:58 +0200 Subject: [PATCH 42/55] add rename as build dependency --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index e2f5087..db7f0ad 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Section: net Priority: optional Maintainer: Mathias Ertl Standards-Version: 3.9.2 -Build-Depends: debhelper (>= 9), python3-all +Build-Depends: debhelper (>= 9), python3-all, rename Vcs-Browser: https://github.com/mathiasertl/db-backup Vcs-Git: https://github.com/mathiasertl/db-backup.git From b9f54333a1954f2e1e55ec6b743561fb89fc0071 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Thu, 24 Oct 2019 21:58:20 +0200 Subject: [PATCH 43/55] add --no-timeout option to ejabberdctl --- dbdump/dbdump.conf.example | 3 +++ dbdump/dbdump.py | 1 + dbdump/libdump/ejabberd.py | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/dbdump/dbdump.conf.example b/dbdump/dbdump.conf.example index 71bb318..7cf032c 100644 --- a/dbdump/dbdump.conf.example +++ b/dbdump/dbdump.conf.example @@ -81,6 +81,9 @@ remote = user@backup.example.com # Dump database from this ejabberd node (optional): #ejabberd-node = ejabberd +# Any other command-line arguments to ejabberd +#ejabberd-options = --no-timeout + # Authenticate with the erlang node. This specifies a normal account on # the jabber server (optional): #ejabberd-auth = user jabber.example.com password diff --git a/dbdump/dbdump.py b/dbdump/dbdump.py index 31d86ea..1552221 100755 --- a/dbdump/dbdump.py +++ b/dbdump/dbdump.py @@ -54,6 +54,7 @@ def err(msg, *args): 'datadir': '/var/backups/%(backend)s', 'mysql-ignore-tables': '', 'ejabberd-base-dir': '/var/lib/ejabberd', + 'ejabberd-options': '--no-timeout', # https://github.com/processone/ejabberd/issues/866 'ssh-timeout': '10', 'ssh-options': '', }) diff --git a/dbdump/libdump/ejabberd.py b/dbdump/libdump/ejabberd.py index 6d1721c..e9b9d60 100644 --- a/dbdump/libdump/ejabberd.py +++ b/dbdump/libdump/ejabberd.py @@ -12,6 +12,7 @@ # see . import os +import shlex import subprocess from libdump import backend @@ -27,7 +28,7 @@ def get_command(self, database): return ['cat', path] def prepare_db(self, database): - cmd = ['ejabberdctl'] + cmd = ['ejabberdctl'] + shlex.split(self.section['ejabberd-options']) if 'ejabberd-node' in self.section: cmd += ['--node', self.section['ejabberd-node']] if 'ejabberd-auth' in self.section: From acd86c92fa100ada0f742abcc985346fe6c9d268 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Thu, 24 Oct 2019 22:03:16 +0200 Subject: [PATCH 44/55] ignore .tox --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c9b568f..087e8f2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ *.pyc *.swp +/.tox/ From b5d5f553b7d53b31456ec6c8c6bc40a3d317f074 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Thu, 24 Oct 2019 22:03:22 +0200 Subject: [PATCH 45/55] add py38 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 099c81c..f5dcc3f 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] # https://devguide.python.org/#status-of-python-branches -envlist = py{35,36,37} +envlist = py{35,36,37,38} [testenv] deps = From ab36e5220bcdd33d7650089942dd8694b7bd6482 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Thu, 24 Oct 2019 22:03:31 +0200 Subject: [PATCH 46/55] style --- dbclean/dbclean.py | 6 +++--- dbdump/libdump/mysql.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dbclean/dbclean.py b/dbclean/dbclean.py index 396e145..a4ea2ac 100755 --- a/dbclean/dbclean.py +++ b/dbclean/dbclean.py @@ -169,12 +169,12 @@ def __str__(self): continue if bck.is_daily() and bck_seconds > now - (daily * 86400): - continue + continue if bck.is_monthly() and bck_seconds > now - (monthly * 2678400): - continue + continue if bck.is_yearly() and bck_seconds > now - (yearly * 31622400): - continue + continue bck.remove() diff --git a/dbdump/libdump/mysql.py b/dbdump/libdump/mysql.py index 50b3e83..e3081d2 100644 --- a/dbdump/libdump/mysql.py +++ b/dbdump/libdump/mysql.py @@ -67,7 +67,7 @@ def get_command(self, database): ignored = [t for t in ignored_tables if t.startswith("%s." % database)] # assemble query for used engines in the database - engine_query = "select ENGINE from information_schema.TABLES WHERE TABLE_SCHEMA='%s' AND ENGINE != 'MEMORY'" % database + engine_query = "select ENGINE from information_schema.TABLES WHERE TABLE_SCHEMA='%s' AND ENGINE != 'MEMORY'" % database # NOQA for table in ignored: engine_query += " AND TABLE_NAME != '%s'" % table.split('.')[1] engine_query += ' GROUP BY ENGINE' From a34ea7ae080500456305a93d1a6291c9b899ae92 Mon Sep 17 00:00:00 2001 From: Mathias Ertl Date: Thu, 24 Oct 2019 22:03:43 +0200 Subject: [PATCH 47/55] update reqs --- requirements-dev.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index df6fd48..0bf631b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,2 +1,2 @@ -flake8==3.6.0 -isort==4.3.4 +flake8==3.7.8 +isort==4.3.21 From ea1935bc125e00a9e1e279d9c76c841f25547cb3 Mon Sep 17 00:00:00 2001 From: David Kaufmann Date: Mon, 22 Jul 2019 03:03:54 +0200 Subject: [PATCH 48/55] fix DeprecationWarning for SafeConfigParser in dbclean too --- dbclean/dbclean.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbclean/dbclean.py b/dbclean/dbclean.py index a4ea2ac..1e1c6e7 100755 --- a/dbclean/dbclean.py +++ b/dbclean/dbclean.py @@ -50,7 +50,7 @@ def err(msg, *args): if args.section == 'DEFAULT': parser.error("--section must not be 'DEFAULT'.") -config = configparser.SafeConfigParser({ +config = configparser.ConfigParser({ 'format': '%%Y-%%m-%%d_%%H:%%M:%%S', 'hourly': '24', 'daily': '31', 'monthly': '12', 'yearly': '3', From 0b1d11ec5ab531afcb1213a18ea595c5854964e6 Mon Sep 17 00:00:00 2001 From: David Kaufmann Date: Mon, 21 Dec 2020 00:15:09 +0100 Subject: [PATCH 49/55] use connectstring for connecting to databases --- dbdump/dbdump.conf.example | 1 + dbdump/libdump/postgresql.py | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/dbdump/dbdump.conf.example b/dbdump/dbdump.conf.example index 7cf032c..cd51593 100644 --- a/dbdump/dbdump.conf.example +++ b/dbdump/dbdump.conf.example @@ -70,6 +70,7 @@ remote = user@backup.example.com # POSTGRESQL OPTIONS: # Additional command-line parameters for psql and pgdump (optional): +#postgresql-connectstring = host=localhost port=5432 #postgresql-psql-opts = --someopt #postgresql-pgdump-opts = --otheropt diff --git a/dbdump/libdump/postgresql.py b/dbdump/libdump/postgresql.py index af2d08d..2ccdee0 100644 --- a/dbdump/libdump/postgresql.py +++ b/dbdump/libdump/postgresql.py @@ -19,14 +19,18 @@ class postgresql(backend.backend): def get_db_list(self): - cmd = ['psql', '-Aqt', '-c', '"select datname from pg_database"'] + cmd = ['psql', '-Aqt', '-c', 'select datname from pg_database'] if 'postgresql-psql-opts' in self.section: cmd += self.section['postgresql-psql-opts'].split(' ') + if 'postgresql-connectstring' in self.section: + cmd.append(self.section['postgresql-connectstring']) + if 'su' in self.section: + quoted_args = [f"\"{arg}\"" if ' ' in arg else arg for arg in cmd ] cmd = ['su', self.section['su'], '-s', '/bin/bash', '-c', - ' '.join(cmd)] + ' '.join(quoted_args)] p_list = Popen(cmd, stdout=PIPE, stderr=PIPE) stdout, stderr = p_list.communicate() @@ -44,5 +48,12 @@ def get_command(self, database): cmd = ['pg_dump', '-c'] if 'postgresql-pgdump-opts' in self.section: cmd += self.section['postgresql-pgdump-opts'].split(' ') - cmd.append(database) + + connectstring_options = [] + if 'postgresql-connectstring' in self.section: + connectstring_options = self.section['postgresql-connectstring'].split(' ') + + connectstring_options.append(f"dbname={database}") + cmd.append(' '.join(connectstring_options)) + return cmd From 7ce1fad282e757cbaafa5d57179beb1cfdd35c10 Mon Sep 17 00:00:00 2001 From: David Kaufmann Date: Wed, 8 Nov 2023 02:55:29 +0100 Subject: [PATCH 50/55] add borg backup support --- dbdump/dbdump.conf.example | 8 +++++++ dbdump/dbdump.py | 2 +- dbdump/libdump/backend.py | 47 +++++++++++++++++++++++++++++++++++++- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/dbdump/dbdump.conf.example b/dbdump/dbdump.conf.example index cd51593..25fd734 100644 --- a/dbdump/dbdump.conf.example +++ b/dbdump/dbdump.conf.example @@ -24,6 +24,14 @@ # unchanged (optional): remote = user@backup.example.com +# Store dumps with borgbackup. Specify the common directory, each db will have +# its own repository. +#borg = user@backup.example.com + +# Encrypt borg backups, store the keyfile on the server and encrypt it with the +# password specified in borg-key, if this parameter is given. +#borg-key = add-a-secret-password-here + # Override the default ssh connect-timeout of 10 seconds: #ssh-timeout = 10 diff --git a/dbdump/dbdump.py b/dbdump/dbdump.py index f37c8cb..a787a07 100755 --- a/dbdump/dbdump.py +++ b/dbdump/dbdump.py @@ -71,7 +71,7 @@ def err(msg, *args): section = config[args.section] -if 'remote' not in section: +if 'remote' not in section and 'borg' not in section: # Note that if we dump to a remote location, there is no real way to check to check if datadir # exists and is writeable. We have to rely on the competence of the admin in that case. datadir = section['datadir'] diff --git a/dbdump/libdump/backend.py b/dbdump/libdump/backend.py index bdb7dae..b5a3e4d 100644 --- a/dbdump/libdump/backend.py +++ b/dbdump/libdump/backend.py @@ -71,7 +71,52 @@ def dump(self, db, timestamp): sha = ['sha256sum'] sed = ['sed', 's/-$/%s/' % os.path.basename(path)] - if 'remote' in self.section: + if 'borg' in self.section: + borg_check = ['borg', 'info'] + borg_init = ['borg', 'init', '--umask', '0077', '--make-parent-dirs'] + borg_create = ['borg', 'create', '--umask', '0077', '--noctime', '--nobirthtime', '--compression', 'zstd', '--files-cache', 'disabled', '--content-from-command', '--'] + borg_repo = self.section['borg'] + + borg_env = os.environ.copy() + borg_env['BORG_RELOCATED_REPO_ACCESS_IS_OK'] = 'yes' + + if 'borg-key' in self.section: + borg_env['BORG_PASSPHRASE'] = self.section['borg-key'] + borg_init += ['--encryption', 'repokey-blake2'] + else: + borg_env['BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK'] = 'yes' + borg_init += ['--encryption', 'none'] + + borg_check += [f"{borg_repo}/{db}"] + borg_init += [f"{borg_repo}/{db}"] + borg_create += [f"{borg_repo}/{db}" + "::" + f"{timestamp}"] + borg_create += cmd + + if self.args.verbose: + str_cmds = [' '.join(c) for c in cmd] + print('# Dump databases:') + print(' | '.join(str_cmds)) + + # check if repo already exists + p_check = Popen(borg_check, env=borg_env, stdout=PIPE) + stdout, stderr = p_check.communicate() + if p_check.returncode != 0: + # repo is missing, create it + p_init = Popen(borg_init, env=borg_env, stdout=PIPE) + stdout, stderr = p_init.communicate() + if p_init.returncode != 0: + raise RuntimeError(f"{borg_init} returned with exit code {p_init.returncode}. (stderr: {stderr})") + + # create backup + p_create = Popen(borg_create, env=borg_env, stdout=PIPE) + stdout, stderr = p_create.communicate() + if self.args.verbose: + print("# borg_create:") + print(' | '.join) + if p_create.returncode != 0: + raise RuntimeError(f"{borg_create} returned with exit code {p_create.returncode}. (stderr: {stderr})") + + elif 'remote' in self.section: ssh = self.get_ssh(path, [tee, sha, sed]) cmds = [cmd, gzip, ] # just for output From 5805b9dfdc566bb128b22989c2fd4efb05892afe Mon Sep 17 00:00:00 2001 From: David Kaufmann Date: Thu, 9 Sep 2021 00:10:49 +0200 Subject: [PATCH 51/55] update changelog --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 8902d02..23f6fd0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +db-backup (2021-09-09-1) unstable; urgency=medium + + * remove deprecation warning for dbclean too + + -- David Kaufmann Wed, 08 Sep 2021 23:17:36 +0200 + db-backup (2019-07-20-1) unstable; urgency=low [ David Kaufmann ] From 2458c04b3deb105825c4e9579397a5ac34266276 Mon Sep 17 00:00:00 2001 From: David Kaufmann Date: Thu, 9 Sep 2021 00:45:17 +0200 Subject: [PATCH 52/55] update debian/control to debhelper v10 --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index db7f0ad..356941a 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Section: net Priority: optional Maintainer: Mathias Ertl Standards-Version: 3.9.2 -Build-Depends: debhelper (>= 9), python3-all, rename +Build-Depends: debhelper (>= 10), python3-all, rename Vcs-Browser: https://github.com/mathiasertl/db-backup Vcs-Git: https://github.com/mathiasertl/db-backup.git From 44052362a06325e201839024dd23f4599303c9dd Mon Sep 17 00:00:00 2001 From: David Kaufmann Date: Thu, 9 Sep 2021 00:51:10 +0200 Subject: [PATCH 53/55] add dh-python to control --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 356941a..4e3d9f3 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Section: net Priority: optional Maintainer: Mathias Ertl Standards-Version: 3.9.2 -Build-Depends: debhelper (>= 10), python3-all, rename +Build-Depends: debhelper (>= 10), dh-python, python3-all, rename Vcs-Browser: https://github.com/mathiasertl/db-backup Vcs-Git: https://github.com/mathiasertl/db-backup.git From 6582d09d51f7e4d686388bff4901847fa008a1ac Mon Sep 17 00:00:00 2001 From: David Kaufmann Date: Thu, 9 Sep 2021 00:53:30 +0200 Subject: [PATCH 54/55] update debian-compat to 10 --- debian/compat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/compat b/debian/compat index ec63514..f599e28 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -9 +10 From 4585b3e997e6d0fe9d4fa9e58fa0e24f5fb25ace Mon Sep 17 00:00:00 2001 From: David Kaufmann Date: Wed, 8 Nov 2023 03:48:08 +0100 Subject: [PATCH 55/55] update changelog --- debian/changelog | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/debian/changelog b/debian/changelog index 23f6fd0..2edfeb3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,23 @@ +db-backup (2023-11-08-1) unstable; urgency=low + + [ Mathias Ertl ] + * add --no-timeout option to ejabberdctl + * ignore .tox + * add py38 + * style + * update reqs + + [ David Kaufmann ] + * fix DeprecationWarning for SafeConfigParser in dbclean too + * use connectstring for connecting to databases + * add borg backup support + * update changelog + * update debian/control to debhelper v10 + * add dh-python to control + * update debian-compat to 10 + + -- David Kaufmann Wed, 08 Nov 2023 03:47:28 +0100 + db-backup (2021-09-09-1) unstable; urgency=medium * remove deprecation warning for dbclean too