diff --git a/storage/backups/borg/backup2.py b/storage/backups/borg/backup2.py index 91c8ccb..a34c5a3 100755 --- a/storage/backups/borg/backup2.py +++ b/storage/backups/borg/backup2.py @@ -9,6 +9,7 @@ import configparser import datetime import json import logging +import logging.handlers import os import subprocess import sys @@ -17,6 +18,11 @@ try: has_mysql = True except ImportError: has_mysql = False +try: + from systemd import journal + has_systemd = True +except ImportError: + has_systemd = False ### LOG LEVEL MAPPINGS ### loglvls = {'critical': logging.CRITICAL, @@ -25,13 +31,57 @@ loglvls = {'critical': logging.CRITICAL, 'info': logging.INFO, 'debug': logging.DEBUG} +### THE GUTS ### class Backup(object): def __init__(self, args): self.args = args # Set up logging - logging.basicConfig(level = self.args['loglevel']) - logger = logging.getLogger(__name__) - pass + _logfmt = logging.Formatter(fmt = '{levelname}:{name}: {message} ({asctime}; {filename}:{lineno})', + style = '{', + datefmt = '%Y-%m-%d %H:%M:%S') + handlers = [] + if self.args['disklog']: + handlers.append(logging.handlers.RotatingFileHandler(self.args['logfile'], + encoding = 'utf8', + maxBytes = 100000, + backupCount = 1)) + handlers.append(logging.StreamHandler()) + self.logger = logging.getLogger(__name__) + self.logger.setLevel(logging.DEBUG) + for h in handlers: + h.setFormatter(_logfmt) + h.setLevel(loglvls[self.args['loglevel']]) + self.logger.addHandler(h) + + def create(self): + pass + + def miscBak(self, pkgr): + pass + + def mysqlBak(self): + pass + + def listRepos(self): + pass + + def printer(self): + pass + + def lister(self): + pass + +def printMoarHelp(): + helpstr = ('\n\tNOTE: Sorting only applies to listing archives, NOT the contents!\n\n' + + 'In order to efficiently display results, there are several options to handle it. ' + + 'Namely, these are:\n\n\t\t-s/--sort [direction]\n\t\t-l/--limit [number]\n\t\t-x/--invert\n\n' + + 'For example, if you want to list the 5 most recently *taken* snapshots, you would use:\n\n\t\t-l 5\n\n' + + 'If you would want those SAME results SORTED in the reverse order (i.e. the 5 most recently ' + + 'taken snapshots sorted from newest to oldest), then it would be: \n\n\t\t-l 5 -x\n\n' + + 'Lastly, if you wanted to list the 7 OLDEST TAKEN snapshots in reverse order (that is, ' + + 'sorted from newest to oldest), that\'d be: \n\n\t\t-o -l 7 -x\n') + print(helpstr) + exit(0) def parseArgs(): ### DEFAULTS ### @@ -39,38 +89,39 @@ def parseArgs(): _logfile = '/var/log/borg/{0}'.format(_date) _mysqldir = os.path.abspath(os.path.join(os.path.expanduser('~'), 'bak', 'mysql')) _stagedir = '/root/bak/misc' - _cfgfile = os.path.abspath(os.path.join(os.path.expanduser('~')), - '.backcfg.json') + _cfgfile = os.path.abspath(os.path.join(os.path.expanduser('~'), '.config', 'optools', 'backup.json')) _defloglvl = 'info' ###### args = argparse.ArgumentParser(description = 'Backups manager', epilog = 'TIP: this program has context-specific help. e.g. try "%(prog)s list --help"') + args.add_argument('-c', '--config', + dest = 'cfgfile', + default = _cfgfile, + help = ('The path to the config file. Default: \033[1m{0}\033[0m'.format(_cfgfile))) + args.add_argument('-Ll', '--loglevel', + dest = 'loglevel', + default = _defloglvl, + choices = list(loglvls.keys()), + help = 'The level of logging to perform. Default: \033[1m{0}\033[0m'.format(_defloglvl)) + args.add_argument('-Ld', '--log-to-disk', + dest = 'disklog', + action = 'store_true', + help = ('If specified, log to a specific file (-Lf/--logfile)' + + ' instead of the system logger.')) + args.add_argument('-Lf', '--logfile', + dest = 'logfile', + default = _logfile, + help = ('The path to the logfile, only used if -Ld/--log-to-disk ' + + 'is specified. Default: \033[1m{0}\033[0m (dynamic)').format(_logfile)) + ### ARGS FOR ALL OPERATIONS ### commonargs = argparse.ArgumentParser(add_help = False) - commonargs.add_argument('-r', - '--repo', + commonargs.add_argument('-r', '--repo', dest = 'repo', + default = 'all', help = ('The repository to perform the operation for. ' + - 'The default is \'all\', a special value that specifies all known ' + - 'repositories. Can also accept a comma-separated list.'), - default = 'all') - commonargs.add_argument('-L', - '--loglevel', - dest = 'loglevel', - default = _defloglvl, - choices = list(loglvls.keys()), - help = 'The level of logging to perform. Default: {0}'.format(_defloglvl)) - commonargs.add_argument('-Ld', - '--log-to-disk', - dest = 'disklog', - action = 'store_true', - help = ('If specified, log to a specific file (-Lf/--logfile)' + - ' instead of the system logger.')) - commonargs.add_argument('-Lf', - '--logfile', - dest = 'logfile', - default = _logfile, - help = ('The path to the logfile, only used if -Ld/--log-to-disk ' + - 'is specified. Default: {0} (dynamic)').format(_logfile)) + 'The default is \033[1mall\033[0m, a special value that specifies all known ' + + 'repositories. Can also accept a comma-separated list.')) + ### OPERATIONS ### subparsers = args.add_subparsers(help = 'Operation to perform', dest = 'oper') backupargs = subparsers.add_parser('backup', @@ -85,17 +136,20 @@ def parseArgs(): initargs = subparsers.add_parser('init', help = 'Initialise a repository.', parents = [commonargs]) + ### OPERATION-SPECIFIC OPTIONS ### + # CREATE ("backup") # backupargs.add_argument('-a', '--archive', default = _date, dest = 'archive', - help = ('The name of the archive. Default: {0} (dynamic)').format(_date)) + help = ('The name of the archive. Default: \033[1m{0}\033[0m (dynamic)').format(_date)) backupargs.add_argument('-s', '--stagedir', default = _stagedir, dest = 'stagedir', help = ('The directory used for staging temporary files, ' + - 'if necessary. Default: {0}').format(_stagedir)) + 'if necessary. Default: \033[1m{0}\033[0m').format(_stagedir)) + # DISPLAY/OUTPUT ("list") # listargs.add_argument('-a', '--archive', dest = 'archive', @@ -107,39 +161,44 @@ def parseArgs(): type = int, default = '5', help = ('If specified, constrain the outout to this number of ' + - 'results each repo. Default is 5, 0 for unlimited. See -H/--list-help.')) + 'results each repo. Default is \033[1m5\033[0m, use 0 for unlimited. ' + + 'See \033[1m-H/--list-help\033[0m')) listargs.add_argument('-s', '--sort', dest = 'sortby', choices = ['newest', 'oldest'], default = 'oldest', - help = 'The order to sort the results by. See -H/--list-help.') + help = ('The order to sort the results by. See \033[1m-H/--list-help\033[0m. ' + + 'Default: \033[1moldest\033[0m')) listargs.add_argument('-x', '--invert', dest = 'invert', action = 'store_true', - help = 'Invert the order of *results*. See -H/--list-help.') + help = 'Invert the order of results. See \033[1m-H/--list-help\033[0m.') listargs.add_argument('-o', '--old', dest = 'old', action = 'store_true', help = ('Instead of grabbing the latest results, grab the earliest results. ' + - 'This differs from -s/--sort. See -H/--list-help.')) + 'This differs from \033[1m-s/--sort\033[0m. See \033[1m-H/--list-help\033[0m.')) listargs.add_argument('-H', '--list-help', dest = 'moarhelp', action = 'store_true', help = 'Print extended information about how to manage the output of listing and exit.') - listargs.add_argument('-v', - '--verbose', - dest = 'verbose', - help = ('Print out detailed information for archive contents ' + - '(only valid if -a is set). WARNING: May include sensitive data.'), - action = 'store_true') return(args) def main(): - args = vars(parseArgs().parse_args()) + rawargs = parseArgs() + args = vars(rawargs.parse_args()) + import pprint # DEBUG + pprint.pprint(args) # DEBUG + if not args['oper']: + rawargs.print_help() + exit(0) + if 'moarhelp' in args.keys() and args['moarhelp']: + printMoarHelp() + bak = Backup(args) if __name__ == '__main__': - main() \ No newline at end of file + main()