Refactor pre/post exec hooks

This commit is contained in:
deajan 2024-10-29 19:35:23 +01:00
parent 2c70dabf1b
commit a2582bebf7

View file

@ -1090,6 +1090,9 @@ class NPBackupRunner:
""" """
Run backup after checking if no recent backup exists, unless force == True Run backup after checking if no recent backup exists, unless force == True
""" """
start_time = datetime.now(timezone.utc)
stdin_from_command = self.repo_config.g("backup_opts.stdin_from_command") stdin_from_command = self.repo_config.g("backup_opts.stdin_from_command")
if not stdin_filename: if not stdin_filename:
stdin_filename = self.repo_config.g("backup_opts.stdin_filename") stdin_filename = self.repo_config.g("backup_opts.stdin_filename")
@ -1228,67 +1231,105 @@ class NPBackupRunner:
else: else:
raise ValueError("Unknown source type given") raise ValueError("Unknown source type given")
pre_exec_commands_success = True def _exec_commands(
if pre_exec_commands: exec_type: str,
for pre_exec_command in pre_exec_commands: command_list: List[str],
exit_code, output = command_runner( per_command_timeout: int,
pre_exec_command, shell=True, timeout=pre_exec_per_command_timeout failure_is_fatal: bool,
)
if exit_code != 0:
msg = f"Pre-execution of command {pre_exec_command} failed with:\n{output}"
self.write_logs(msg, level="error")
if pre_exec_failure_is_fatal:
return self.convert_to_json_output(False, msg)
else:
self.write_logs(msg, level="warning")
pre_exec_commands_success = False
else:
self.write_logs(
f"Pre-execution of command {pre_exec_command} succeeded with:\n{output}",
level="info",
)
# Run actual backup here
if source_type in (
None,
"folder_list",
"files_from_verbatim",
"files_from_raw",
): ):
result = self.restic_runner.backup( commands_success = True
paths=paths, if command_list:
source_type=source_type, for command in command_list:
exclude_patterns=exclude_patterns, exit_code, output = command_runner(
exclude_files=exclude_files, command, shell=True, timeout=per_command_timeout
excludes_case_ignore=excludes_case_ignore, )
exclude_caches=exclude_caches, if exit_code != 0:
exclude_files_larger_than=exclude_files_larger_than, msg = f"{exec_type}-execution of command {command} failed with:\n{output}"
one_file_system=one_file_system, commands_success = False
use_fs_snapshot=use_fs_snapshot, if not failure_is_fatal:
tags=tags, self.write_logs(msg, level="warning")
additional_backup_only_parameters=additional_backup_only_parameters, else:
) self.write_logs(msg, level="error")
elif source_type == "stdin_from_command" and stdin_from_command: self.write_logs(
result = self.restic_runner.backup( "Stopping further execution due to fatal error",
stdin_from_command=stdin_from_command, level="error",
stdin_filename=stdin_filename, )
tags=tags, break
additional_backup_only_parameters=additional_backup_only_parameters, else:
) self.write_logs(
elif read_from_stdin: f"{exec_type}-execution of command {command} succeeded with:\n{output}",
result = self.restic_runner.backup( level="info",
read_from_stdin=read_from_stdin, )
stdin_filename=stdin_filename, return commands_success
tags=tags,
additional_backup_only_parameters=additional_backup_only_parameters,
)
else:
raise ValueError("Bogus backup source type given")
self.write_logs( pre_exec_commands_success = _exec_commands(
f"Restic output:\n{self.restic_runner.backup_result_content}", level="debug" "Pre",
pre_exec_commands,
pre_exec_per_command_timeout,
pre_exec_failure_is_fatal,
) )
if pre_exec_failure_is_fatal and not pre_exec_commands_success:
# This logic is more readable than it's negation, let's just keep it
result = False
else:
# Run actual backup here
if source_type in (
None,
"folder_list",
"files_from_verbatim",
"files_from_raw",
):
result = self.restic_runner.backup(
paths=paths,
source_type=source_type,
exclude_patterns=exclude_patterns,
exclude_files=exclude_files,
excludes_case_ignore=excludes_case_ignore,
exclude_caches=exclude_caches,
exclude_files_larger_than=exclude_files_larger_than,
one_file_system=one_file_system,
use_fs_snapshot=use_fs_snapshot,
tags=tags,
additional_backup_only_parameters=additional_backup_only_parameters,
)
elif source_type == "stdin_from_command" and stdin_from_command:
result = self.restic_runner.backup(
stdin_from_command=stdin_from_command,
stdin_filename=stdin_filename,
tags=tags,
additional_backup_only_parameters=additional_backup_only_parameters,
)
elif read_from_stdin:
result = self.restic_runner.backup(
read_from_stdin=read_from_stdin,
stdin_filename=stdin_filename,
tags=tags,
additional_backup_only_parameters=additional_backup_only_parameters,
)
else:
raise ValueError("Bogus backup source type given")
self.write_logs(
f"Restic output:\n{self.restic_runner.backup_result_content}",
level="debug",
)
post_exec_commands_success = _exec_commands(
"Post",
post_exec_commands,
post_exec_per_command_timeout,
post_exec_failure_is_fatal,
)
# So we must duplicate @exec_time code here since we must call @metrics manually
# because it will need restic output from backup function
self.exec_time = (datetime.now(timezone.utc) - start_time).total_seconds()
try:
os.environ["NPBACKUP_EXEC_TIME"] = str(self.exec_time)
except OSError:
pass
# Extract backup size from result_string # Extract backup size from result_string
# Metrics will not be in json format, since we need to diag cloud issues until # Metrics will not be in json format, since we need to diag cloud issues until
# there is a fix for https://github.com/restic/restic/issues/4155 # there is a fix for https://github.com/restic/restic/issues/4155
@ -1304,26 +1345,6 @@ class NPBackupRunner:
"Backup is smaller than configured minmium backup size", level="error" "Backup is smaller than configured minmium backup size", level="error"
) )
post_exec_commands_success = True
if post_exec_commands:
for post_exec_command in post_exec_commands:
exit_code, output = command_runner(
post_exec_command, shell=True, timeout=post_exec_per_command_timeout
)
if exit_code != 0:
msg = f"Post-execution of command {post_exec_command} failed with:\n{output}"
self.write_logs(msg, level="error")
post_exec_commands_success = False
if post_exec_failure_is_fatal:
return self.convert_to_json_output(False, msg)
else:
self.write_logs(msg, level="warning")
else:
self.write_logs(
f"Post-execution of command {post_exec_command} succeeded with:\n{output}",
level="info",
)
operation_result = ( operation_result = (
result result
and pre_exec_commands_success and pre_exec_commands_success
@ -1336,6 +1357,7 @@ class NPBackupRunner:
level="info" if operation_result else "error", level="info" if operation_result else "error",
ignore_additional_json=True, ignore_additional_json=True,
) )
if not operation_result: if not operation_result:
# patch result if json # patch result if json
if isinstance(result, dict): if isinstance(result, dict):