From ee1beb9b5b8aab8c8f948942d397fd2298443048 Mon Sep 17 00:00:00 2001 From: Paul Hoffmann Date: Thu, 30 Mar 2023 16:02:19 +0200 Subject: [PATCH] Add ntfy warning --- borgmatic/commands/borgmatic.py | 11 +++++++++++ borgmatic/commands/warning.py | 2 ++ borgmatic/config/schema.yaml | 24 ++++++++++++++++++++++++ borgmatic/execute.py | 23 +++++++++++++++++++++++ borgmatic/hooks/monitor.py | 1 + 5 files changed, 61 insertions(+) create mode 100644 borgmatic/commands/warning.py diff --git a/borgmatic/commands/borgmatic.py b/borgmatic/commands/borgmatic.py index b4aadfca..e3c1cf17 100644 --- a/borgmatic/commands/borgmatic.py +++ b/borgmatic/commands/borgmatic.py @@ -29,6 +29,7 @@ import borgmatic.actions.transfer import borgmatic.commands.completion from borgmatic.borg import umount as borg_umount from borgmatic.borg import version as borg_version +from borgmatic.commands import warning from borgmatic.commands.arguments import parse_arguments from borgmatic.config import checks, collect, convert, validate from borgmatic.hooks import command, dispatch, monitor @@ -151,6 +152,16 @@ def run_configuration(config_filename, config, arguments): encountered_error = error error_repository = repository['path'] + except warning.BorgmaticWarning: + dispatch.call_hooks( + 'ping_monitor', + hooks, + config_filename, + monitor.MONITOR_HOOK_NAMES, + monitor.State.WARN, + monitoring_log_level, + global_arguments.dry_run, + ) try: if using_primary_action: # send logs irrespective of error diff --git a/borgmatic/commands/warning.py b/borgmatic/commands/warning.py new file mode 100644 index 00000000..ee78f37e --- /dev/null +++ b/borgmatic/commands/warning.py @@ -0,0 +1,2 @@ +class BorgmaticWarning(Warning): + pass diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 469b1f52..4dfd4a12 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1179,6 +1179,29 @@ properties: description: | Tags to attach to the message. example: incoming_envelope + warn: + type: object + properties: + title: + type: string + description: | + The title of the message. + example: Ping! + message: + type: string + description: | + The message body to publish. + example: Your backups ended with warnings + priority: + type: string + description: | + The priority to set. + example: urgent + tags: + type: string + description: | + Tags to attach to the message. + example: incoming_envelope states: type: array items: @@ -1187,6 +1210,7 @@ properties: - start - finish - fail + - warn uniqueItems: true description: | List of one or more monitoring states to ping for: diff --git a/borgmatic/execute.py b/borgmatic/execute.py index 0afa5cca..983663e1 100644 --- a/borgmatic/execute.py +++ b/borgmatic/execute.py @@ -4,11 +4,14 @@ import os import select import subprocess +from borgmatic.commands import warning + logger = logging.getLogger(__name__) ERROR_OUTPUT_MAX_LINE_COUNT = 25 BORG_ERROR_EXIT_CODE = 2 +BORG_WARNING_EXIT_CODE = 1 def exit_code_indicates_error(command, exit_code, borg_local_path=None): @@ -26,6 +29,21 @@ def exit_code_indicates_error(command, exit_code, borg_local_path=None): return bool(exit_code != 0) +def exit_code_indicates_borg_warning(process, exit_code, borg_local_path=None): + ''' + Return True if the given exit code from running a borg command corresponds to an borg warning. + ''' + if exit_code is None: + return False + + command = process.args.split(' ') if isinstance(process.args, str) else process.args + + if borg_local_path and command[0] == borg_local_path: + return bool(exit_code == BORG_WARNING_EXIT_CODE) + + return False + + def command_for_process(process): ''' Given a process as an instance of subprocess.Popen, return the command string that was used to @@ -134,6 +152,10 @@ def log_outputs(processes, exclude_stdouts, output_log_level, borg_local_path): still_running = True command = process.args.split(' ') if isinstance(process.args, str) else process.args + + if exit_code_indicates_borg_warning(process, exit_code, borg_local_path): + raise warning.BorgmaticWarning() + # If any process errors, then raise accordingly. if exit_code_indicates_error(command, exit_code, borg_local_path): # If an error occurs, include its output in the raised exception so that we don't @@ -227,6 +249,7 @@ def execute_command( env=environment, cwd=working_directory, ) + if not run_to_completion: return process diff --git a/borgmatic/hooks/monitor.py b/borgmatic/hooks/monitor.py index c0168178..8b3cf1e8 100644 --- a/borgmatic/hooks/monitor.py +++ b/borgmatic/hooks/monitor.py @@ -8,3 +8,4 @@ class State(Enum): FINISH = 2 FAIL = 3 LOG = 4 + WARN = 5