This commit is contained in:
Edwin Eefting 2019-10-19 20:24:42 +02:00
parent 6b50460542
commit 5cb98589bf

View File

@ -9,11 +9,13 @@ import subprocess
import pprint
# import cStringIO
import time
import argparse
class Log:
def __init__(self):
def __init__(self, show_debug=False, show_verbose=False):
self.titles=[]
pass
self.show_debug=show_debug
self.show_verbose=show_verbose
def titled_str(self, txt, titles):
"""magic to make our log messages ident and more clear"""
@ -35,15 +37,14 @@ class Log:
print(txt, file=sys.stderr)
def verbose(self, txt, titles=[]):
if args.verbose:
if self.show_verbose:
print(self.titled_str(txt, titles))
def debug(self, txt, titles=[]):
if args.debug:
print(txt)
if self.show_debug:
print(self.titled_str(txt, titles))
log=Log()
#fatal abort execution, exit code 255
def abort(txt):
@ -87,6 +88,7 @@ class cached_property(object):
class ExecuteNode:
"""an endpoint to execute local or remote commands via ssh"""
def __init__(self, ssh_to=None, readonly=False):
"""ssh_to: server you want to ssh to. none means local
readonly: only execute commands that dont make any changes (usefull for testing-runs)
@ -122,12 +124,12 @@ class ExecuteNode:
debug_txt="# "+" ".join(encoded_cmd)
if self.readonly and not readonly:
log.debug("[NOT EXECUTING (readonly mode)] "+debug_txt)
self.debug("[NOT EXECUTING (readonly mode)] "+debug_txt)
else:
log.debug(debug_txt)
self.debug(debug_txt)
if input:
log.debug("INPUT:\n"+input.rstrip())
self.debug("INPUT:\n"+input.rstrip())
stdin=subprocess.PIPE
else:
stdin=None
@ -278,20 +280,24 @@ class ZfsDataset():
class ZfsNode(ExecuteNode):
"""a node that contains zfs datasets. implements global lowlevel zfs commands"""
def __init__(self, backup_name, ssh_to=None, readonly=False, description=""):
def __init__(self, backup_name, zfs_autobackup, ssh_to=None, readonly=False, description=""):
self.backup_name=backup_name
if not description:
self.description=ssh_to
else:
self.description=description
self.zfs_autobackup=zfs_autobackup #for logging
ExecuteNode.__init__(self, ssh_to=ssh_to, readonly=readonly)
def verbose(self,txt,titles=[]):
titles.insert(0,self.description)
log.verbose(txt, titles)
self.zfs_autobackup.verbose(txt, titles)
def debug(self,txt, titles=[]):
titles.insert(0,self.description)
log.debug(txt, titles)
self.zfs_autobackup.debug(txt, titles)
def new_snapshotname(self):
"""determine uniq new snapshotname"""
@ -366,13 +372,10 @@ class ZfsNode(ExecuteNode):
class ZfsAutobackup:
"""main class"""
def __init__(self):
################################################################## ENTRY POINT
# parse arguments
import argparse
parser = argparse.ArgumentParser(
description='ZFS autobackup v2.4',
epilog='When a filesystem fails, zfs_backup will continue and report the number of failures at that end. Also the exit code will indicate the number of failures.')
@ -408,17 +411,36 @@ parser.add_argument('--debug', action='store_true', help='debug output (shows co
#note args is the only global variable we use, since its a global readonly setting anyway
args = parser.parse_args()
source_node=ZfsNode(args.backup_name, ssh_to=args.ssh_source, readonly=args.test)
target_node=ZfsNode(args.backup_name, ssh_to=args.ssh_target, readonly=args.test)
self.args=args
self.log=Log(show_debug=self.args.debug, show_verbose=self.args.verbose)
def verbose(self,txt,titles=[]):
titles.insert(0,self.title)
self.log.verbose(txt, titles)
def debug(self,txt,titles=[]):
titles.insert(0,self.title)
self.log.debug(txt, titles)
def set_title(self, title):
self.title=title
def run(self):
description="Source {}".format(self.args.ssh_source or "(local)")
source_node=ZfsNode(self.args.backup_name, self, ssh_to=self.args.ssh_source, readonly=self.args.test, description=description)
description="Target {}".format(self.args.ssh_target or "(local)")
target_node=ZfsNode(self.args.backup_name, self, ssh_to=self.args.ssh_target, readonly=self.args.test, description=description)
self.set_title("Getting selected datasets")
source_datasets=source_node.selected_datasets
if not source_datasets:
abort("No source filesystems selected, please do a 'zfs set autobackup:{0}=true' on {1}".format(args.backup_name,args.ssh_source))
abort("No source filesystems selected, please do a 'zfs set autobackup:{0}=true' on {1}".format(self.args.backup_name, self.args.ssh_source))
source_node.consistent_snapshot(source_datasets, source_node.new_snapshotname(), allow_empty=args.allow_empty)
self.set_title("Snapshotting")
source_node.consistent_snapshot(source_datasets, source_node.new_snapshotname(), allow_empty=self.args.allow_empty)
# for source_dataset in source_datasets:
# print(source_dataset)
@ -426,3 +448,7 @@ source_node.consistent_snapshot(source_datasets, source_node.new_snapshotname(),
#
#
# pprint.pprint(ZfsDataset(node, "rpool").recursive_datasets)
zfs_autobackup=ZfsAutobackup()
zfs_autobackup.run()