Implemented --stdin backup source

This commit is contained in:
Orsiris de Jong 2024-01-04 01:27:21 +01:00
parent 9fed9e31a9
commit 9e9bda9807
3 changed files with 199 additions and 153 deletions

View file

@ -191,6 +191,17 @@ This is free software, and you are welcome to redistribute it under certain cond
action="store_true",
help="Run in JSON API mode. Nothing else than JSON will be printed to stdout",
)
parser.add_argument(
"--stdin",
action="store_true",
help="Backup using data from stdin input"
)
parser.add_argument(
"--stdin-filename",
type=str,
default=None,
help="Alternate filename for stdin, defaults to 'stdin.data'"
)
parser.add_argument(
"-v", "--verbose", action="store_true", help="Show verbose output"
)
@ -289,7 +300,14 @@ This is free software, and you are welcome to redistribute it under certain cond
"op_args": {},
}
if args.backup:
if args.stdin:
cli_args["operation"] = "backup"
cli_args["op_args"] = {
"force": True,
"read_from_stdin": True,
"stdin_filename": args.stdin_filename if args.stdin_filename else None
}
elif args.backup:
cli_args["operation"] = "backup"
cli_args["op_args"] = {"force": args.force}
elif args.restore:

View file

@ -823,11 +823,12 @@ class NPBackupRunner:
@is_ready
@apply_config_to_restic_runner
@catch_exceptions
def backup(self, force: bool = False) -> bool:
def backup(self, force: bool = False, read_from_stdin: bool = False, stdin_filename: str = "stdin.data") -> bool:
"""
Run backup after checking if no recent backup exists, unless force == True
"""
# Preflight checks
if not read_from_stdin:
paths = self.repo_config.g("backup_opts.paths")
if not paths:
self.write_logs(
@ -957,6 +958,7 @@ class NPBackupRunner:
self.restic_runner.verbose = self.verbose
# Run backup here
if not read_from_stdin:
if source_type not in ["folder_list", None]:
self.write_logs(
f"Running backup of files in {paths} list to repo {self.repo_config.g('name')}",
@ -967,6 +969,8 @@ class NPBackupRunner:
f"Running backup of {paths} to repo {self.repo_config.g('name')}",
level="info",
)
else:
self.write_logs(f"Running backup of piped stdin data as name {stdin_filename} to repo {self.repo_config.g('name')}", level="info")
pre_exec_commands_success = True
if pre_exec_commands:
@ -989,6 +993,7 @@ class NPBackupRunner:
)
self.restic_runner.dry_run = self.dry_run
if not read_from_stdin:
result, result_string = self.restic_runner.backup(
paths=paths,
source_type=source_type,
@ -1002,6 +1007,13 @@ class NPBackupRunner:
tags=tags,
additional_backup_only_parameters=additional_backup_only_parameters,
)
else:
result, result_string = self.restic_runner.backup(
read_from_stdin=read_from_stdin,
stdin_filename=stdin_filename,
tags=tags,
additional_backup_only_parameters=additional_backup_only_parameters
)
self.write_logs(f"Restic output:\n{result_string}", level="debug")
# Extract backup size from result_string

View file

@ -253,6 +253,8 @@ class ResticRunner:
errors_allowed: bool = False,
no_output_queues: bool = False,
timeout: int = None,
stdin: sys.stdin = None
) -> Tuple[bool, str]:
"""
Executes restic with given command
@ -276,6 +278,7 @@ class ResticRunner:
timeout=timeout,
split_streams=False,
encoding="utf-8",
stdin=stdin,
stdout=self.stdout if not no_output_queues else None,
stderr=self.stderr if not no_output_queues else None,
no_close_queues=True,
@ -665,8 +668,8 @@ class ResticRunner:
@check_if_init
def backup(
self,
paths: List[str],
source_type: str,
paths: List[str] = None,
source_type: str = None,
exclude_patterns: List[str] = [],
exclude_files: List[str] = [],
excludes_case_ignore: bool = False,
@ -675,6 +678,8 @@ class ResticRunner:
use_fs_snapshot: bool = False,
tags: List[str] = [],
one_file_system: bool = False,
read_from_stdin: bool = False,
stdin_filename: str = "stdin.data",
additional_backup_only_parameters: str = None,
) -> Union[bool, str, dict]:
"""
@ -683,6 +688,11 @@ class ResticRunner:
kwargs = locals()
kwargs.pop("self")
if read_from_stdin:
cmd = "backup --stdin"
if stdin_filename:
cmd += f' --stdin-filename "{stdin_filename}"'
else:
# Handle various source types
if source_type in [
"files_from",
@ -751,10 +761,15 @@ class ResticRunner:
cmd += " --tag {}".format(tag)
if additional_backup_only_parameters:
cmd += " {}".format(additional_backup_only_parameters)
# Run backup
if read_from_stdin:
result, output = self.executor(cmd, stdin=sys.stdin.buffer)
else:
result, output = self.executor(cmd)
if (
use_fs_snapshot
not read_from_stdin and use_fs_snapshot
and not result
and re.search("VSS Error", output, re.IGNORECASE)
):
@ -762,6 +777,7 @@ class ResticRunner:
"VSS cannot be used. Backup will be done without VSS.", level="error"
)
result, output = self.executor(cmd.replace(" --use-fs-snapshot", ""))
if self.json_output:
return self.convert_to_json_output(result, output, **kwargs)
if result: