btrbk_restore_raw.py: add dry-run mode

pull/401/head
fr3aker 2021-08-06 22:33:38 +02:00
parent 7e80e0cbba
commit 025a7709e3
1 changed files with 39 additions and 13 deletions

View File

@ -11,6 +11,9 @@ logger = logging.getLogger(__name__)
class TransformProcess:
def run(self, bfile, options, **kw):
return subprocess.Popen(self.get_cmd(bfile, options), **kw)
def get_cmd(self, bfile, options):
raise NotImplementedError()
@classmethod
@ -20,13 +23,14 @@ class TransformProcess:
class TransformOpensslDecrypt(TransformProcess):
@staticmethod
def run(bfile, options, **kw):
return subprocess.Popen([
def get_cmd(bfile, options):
return [
'openssl', 'enc', '-d', '-' + bfile.info['cipher'], '-K',
open(options.openssl_keyfile, 'r').read(), '-iv', bfile.info['iv']], **kw)
open(options.openssl_keyfile, 'r').read(), '-iv', bfile.info['iv']
]
@classmethod
def add_parser_options(cls, parser):
@staticmethod
def add_parser_options(parser):
parser.add_argument('--openssl-keyfile', help="path to private encryption key file")
@ -34,14 +38,18 @@ class TransformDecompress(TransformProcess):
def __init__(self, program):
self.p = program
def run(self, bfile, options, **kw):
return subprocess.Popen([self.p, '-d'], **kw)
def get_cmd(self, bfile, options):
return [self.p, '-d']
class TransformBtrfsReceive(TransformProcess):
@classmethod
def run(cls, bfile, options, **kw):
return subprocess.Popen(cls.get_cmd(bfile, options), **kw)
@staticmethod
def run(bfile, options, **kw):
return subprocess.Popen(['btrfs', 'receive', options.restore_dir], **kw)
def get_cmd(bfile, options):
return ['btrfs', 'receive', options.restore_dir]
TRANSFORMERS = (
@ -96,6 +104,13 @@ class BtrfsPipeline:
if msg:
logger.error(f"error running {p.args}: {msg}")
def get_cmd(self, options):
command_pipe = [['cat', self.bfile.data_file]]
for transformer in self.processors:
command_pipe.append(transformer.get_cmd(self.bfile, options))
command_pipe.append(TransformBtrfsReceive.get_cmd(self.bfile, options))
return ' | '.join(' '.join(x) for x in command_pipe)
class BackupFile:
def __init__(self, path):
@ -132,11 +147,14 @@ class BackupFile:
def restore_file(self, options):
assert self.info.get('TYPE') == 'raw'
assert not self.info.get('INCOMPLETE')
logger.info(f"restoring backup {os.path.basename(self.data_file)}")
pipeline = BtrfsPipeline(self)
for transformer in self.get_transformers():
pipeline.append(transformer)
pipeline.run(options)
if options.dry_run:
print(pipeline.get_cmd(options))
else:
logger.info(f"restoring backup {os.path.basename(self.data_file)}")
pipeline.run(options)
self.is_restored = True
@ -175,13 +193,21 @@ def main():
parser = argparse.ArgumentParser(description="restore btrbk raw backup")
parser.add_argument('backup', help="backup file to restore; for incremental"
" backups the parent files must be in the same directory")
parser.add_argument('restore_dir', help="target directory for restored subvolumes (path argument for \"btrfs receive\")")
parser.add_argument('--ignore-missing', action='store_true', help="do not fail on missing parent snapshots")
parser.add_argument('restore_dir', help="target directory for restored subvolumes"
" (path argument for \"btrfs receive\")")
parser.add_argument('--ignore-missing', action='store_true',
help="do not fail on missing parent snapshots")
parser.add_argument('--dry-run', '-n', action='store_true',
help="print commmands that would be exectuted")
for transformer in TRANSFORMERS:
transformer.add_parser_options(parser)
args = parser.parse_args()
if args.dry_run:
logger.setLevel('ERROR')
restore_from_path(args.backup, args)