mirror of
https://github.com/netinvent/npbackup.git
synced 2024-09-21 07:16:16 +08:00
Implemented --stdin backup source
This commit is contained in:
parent
9fed9e31a9
commit
9e9bda9807
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue