subprocess-util/btrfs_send_chunks.py

113 lines
3.7 KiB
Python
Raw Normal View History

2023-01-11 13:17:52 +01:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
from pathlib import Path
import shlex
from exec_print_transfer import execute_print_transfer_chunks
from common import _get_chunk_file, _get_remote_socket
from transfer_inform import transfer_inform
def main():
args = parse_args()
command_parts = (
['btrfs', 'send'],
['-p', str(args.parent)] if args.parent else [],
['--compress-data'] if args.compressed_data else [],
[str(args.child)]
)
command = [x for xs in command_parts for x in xs]
execute_print_transfer_chunks(
command=command,
chunk_file_tmpl=args.chunk_tmpl,
chunk_transfer_fun=chunk_transfer_fun,
chunk_transfer_args=(args.ssh_target, args.target_path, args.chunk_tmpl),
chunk_size=args.chunk_size,
)
def parse_args():
parser = argparse.ArgumentParser(prog='btrfs-send-chunks')
parser.add_argument('-p',
help='Parent subvolume; forwarded to btrfs-send.',
dest='parent',
default=None,
type=Path,
metavar='PARENT_SUBVOLUME'
)
parser.add_argument('--compressed-data',
help='Forwarded to btrfs-send.',
dest='compressed_data',
action='store_true',
default=False,
)
parser.add_argument('--chunk-tmpl',
help='During btrfs-send, chunks are saved as "CHUNK_TMPL.CHUNK_NUMBER". '
'The default value of CHUNK_TMPL is "CHILD_SUBVOLUME.CHUNK". '
'One can change it to e.g. "/tmp/chunk/CHILD_SUBVOLUME".',
dest='chunk_tmpl',
default=None,
type=Path,
metavar='CHUNK_TMPL'
)
parser.add_argument('--chunk-size',
help='Size in bytes; defaults to 64 MB.',
dest='chunk_size',
type=int,
default=64 * 1024 * 1024,
)
parser.add_argument('child',
help='Forwarded to btrfs-send.',
type=Path,
metavar='CHILD_SUBVOLUME'
)
parser.add_argument('ssh_target',
help='Hostname of target computer; as configured in ~/.ssh/config.',
metavar='SSH_TARGET'
)
parser.add_argument('target_path',
help='Path where the subvolume will be created on the remote ssh target.',
type=Path,
metavar='TARGET_PATH'
)
args = parser.parse_args()
if not args.chunk_tmpl:
child: Path = args.child
args.chunk_tmpl = child.parent.joinpath(f'{child.name}.CHUNK')
return args
def chunk_transfer_fun(chunk_file: Path, ct: int, eof: bool,
ssh_target: str,
target_path: Path,
chunk_tmpl: Path):
target_chunk = _get_chunk_file(chunk_tmpl, ct)
rsync_cmd = ['rsync', str(chunk_file), f'{ssh_target}:{str(target_chunk)}']
message = 'EOF' if eof else 'OK'
target_socket = _get_remote_socket(target_path)
inform_cmd = ['ssh', ssh_target, f'echo {message} | nc -U {shlex.quote(str(target_socket))}']
transfer_inform(
rsync_cmd=rsync_cmd,
inform_cmd=inform_cmd,
user_input_file=chunk_file.parent.joinpath(f'{chunk_file.name}.SOCKET'),
)
if __name__ == '__main__':
main()