diff --git a/NEWS b/NEWS index 39cb6c25..c4223875 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,7 @@ 1.7.9.dev0 * #295: Add a SQLite database dump/restore hook. + * #628: Add Healthchecks "log" state to send borgmatic logs to Healthchecks without signalling + success or failure. 1.7.8 * #620: With the "create" action and the "--list" ("--files") flag, only show excluded files at diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 92423909..480c1dc6 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1180,7 +1180,8 @@ properties: type: boolean description: | Send borgmatic logs to Healthchecks as part the - "finish" state. Defaults to true. + "finish", "fail", and "log" states. Defaults to + true. example: false ping_body_limit: type: integer @@ -1203,7 +1204,7 @@ properties: uniqueItems: true description: | List of one or more monitoring states to ping for: - "start", "finish", and/or "fail". Defaults to + "start", "finish", "fail", and/or "log". Defaults to pinging for all states. example: - finish diff --git a/borgmatic/hooks/ntfy.py b/borgmatic/hooks/ntfy.py index 3f897aad..8a6f0fb8 100644 --- a/borgmatic/hooks/ntfy.py +++ b/borgmatic/hooks/ntfy.py @@ -2,8 +2,6 @@ import logging import requests -from borgmatic.hooks import monitor - logger = logging.getLogger(__name__) diff --git a/tests/unit/hooks/test_ntfy.py b/tests/unit/hooks/test_ntfy.py index ea3f3c1d..9731df7a 100644 --- a/tests/unit/hooks/test_ntfy.py +++ b/tests/unit/hooks/test_ntfy.py @@ -2,6 +2,7 @@ from enum import Enum from flexmock import flexmock +import borgmatic.hooks.monitor from borgmatic.hooks import ntfy as module default_base_url = 'https://ntfy.sh' @@ -37,12 +38,16 @@ def test_ping_monitor_minimal_config_hits_hosted_ntfy_on_fail(): hook_config = {'topic': topic} flexmock(module.requests).should_receive('post').with_args( f'{default_base_url}/{topic}', - headers=return_default_message_headers(module.monitor.State.FAIL), + headers=return_default_message_headers(borgmatic.hooks.monitor.State.FAIL), auth=None, ).and_return(flexmock(ok=True)).once() module.ping_monitor( - hook_config, 'config.yaml', module.monitor.State.FAIL, monitoring_log_level=1, dry_run=False + hook_config, + 'config.yaml', + borgmatic.hooks.monitor.State.FAIL, + monitoring_log_level=1, + dry_run=False, ) @@ -54,12 +59,16 @@ def test_ping_monitor_with_auth_hits_hosted_ntfy_on_fail(): } flexmock(module.requests).should_receive('post').with_args( f'{default_base_url}/{topic}', - headers=return_default_message_headers(module.monitor.State.FAIL), + headers=return_default_message_headers(borgmatic.hooks.monitor.State.FAIL), auth=module.requests.auth.HTTPBasicAuth('testuser', 'fakepassword'), ).and_return(flexmock(ok=True)).once() module.ping_monitor( - hook_config, 'config.yaml', module.monitor.State.FAIL, monitoring_log_level=1, dry_run=False + hook_config, + 'config.yaml', + borgmatic.hooks.monitor.State.FAIL, + monitoring_log_level=1, + dry_run=False, ) @@ -67,13 +76,17 @@ def test_ping_monitor_auth_with_no_username_warning(): hook_config = {'topic': topic, 'password': 'fakepassword'} flexmock(module.requests).should_receive('post').with_args( f'{default_base_url}/{topic}', - headers=return_default_message_headers(module.monitor.State.FAIL), + headers=return_default_message_headers(borgmatic.hooks.monitor.State.FAIL), auth=None, ).and_return(flexmock(ok=True)).once() flexmock(module.logger).should_receive('warning').once() module.ping_monitor( - hook_config, 'config.yaml', module.monitor.State.FAIL, monitoring_log_level=1, dry_run=False + hook_config, + 'config.yaml', + borgmatic.hooks.monitor.State.FAIL, + monitoring_log_level=1, + dry_run=False, ) @@ -81,13 +94,17 @@ def test_ping_monitor_auth_with_no_password_warning(): hook_config = {'topic': topic, 'username': 'testuser'} flexmock(module.requests).should_receive('post').with_args( f'{default_base_url}/{topic}', - headers=return_default_message_headers(module.monitor.State.FAIL), + headers=return_default_message_headers(borgmatic.hooks.monitor.State.FAIL), auth=None, ).and_return(flexmock(ok=True)).once() flexmock(module.logger).should_receive('warning').once() module.ping_monitor( - hook_config, 'config.yaml', module.monitor.State.FAIL, monitoring_log_level=1, dry_run=False + hook_config, + 'config.yaml', + borgmatic.hooks.monitor.State.FAIL, + monitoring_log_level=1, + dry_run=False, ) @@ -98,7 +115,7 @@ def test_ping_monitor_minimal_config_does_not_hit_hosted_ntfy_on_start(): module.ping_monitor( hook_config, 'config.yaml', - module.monitor.State.START, + borgmatic.hooks.monitor.State.START, monitoring_log_level=1, dry_run=False, ) @@ -111,7 +128,7 @@ def test_ping_monitor_minimal_config_does_not_hit_hosted_ntfy_on_finish(): module.ping_monitor( hook_config, 'config.yaml', - module.monitor.State.FINISH, + borgmatic.hooks.monitor.State.FINISH, monitoring_log_level=1, dry_run=False, ) @@ -121,12 +138,16 @@ def test_ping_monitor_minimal_config_hits_selfhosted_ntfy_on_fail(): hook_config = {'topic': topic, 'server': custom_base_url} flexmock(module.requests).should_receive('post').with_args( f'{custom_base_url}/{topic}', - headers=return_default_message_headers(module.monitor.State.FAIL), + headers=return_default_message_headers(borgmatic.hooks.monitor.State.FAIL), auth=None, ).and_return(flexmock(ok=True)).once() module.ping_monitor( - hook_config, 'config.yaml', module.monitor.State.FAIL, monitoring_log_level=1, dry_run=False + hook_config, + 'config.yaml', + borgmatic.hooks.monitor.State.FAIL, + monitoring_log_level=1, + dry_run=False, ) @@ -135,7 +156,11 @@ def test_ping_monitor_minimal_config_does_not_hit_hosted_ntfy_on_fail_dry_run(): flexmock(module.requests).should_receive('post').never() module.ping_monitor( - hook_config, 'config.yaml', module.monitor.State.FAIL, monitoring_log_level=1, dry_run=True + hook_config, + 'config.yaml', + borgmatic.hooks.monitor.State.FAIL, + monitoring_log_level=1, + dry_run=True, ) @@ -146,7 +171,11 @@ def test_ping_monitor_custom_message_hits_hosted_ntfy_on_fail(): ).and_return(flexmock(ok=True)).once() module.ping_monitor( - hook_config, 'config.yaml', module.monitor.State.FAIL, monitoring_log_level=1, dry_run=False + hook_config, + 'config.yaml', + borgmatic.hooks.monitor.State.FAIL, + monitoring_log_level=1, + dry_run=False, ) @@ -154,14 +183,14 @@ def test_ping_monitor_custom_state_hits_hosted_ntfy_on_start(): hook_config = {'topic': topic, 'states': ['start', 'fail']} flexmock(module.requests).should_receive('post').with_args( f'{default_base_url}/{topic}', - headers=return_default_message_headers(module.monitor.State.START), + headers=return_default_message_headers(borgmatic.hooks.monitor.State.START), auth=None, ).and_return(flexmock(ok=True)).once() module.ping_monitor( hook_config, 'config.yaml', - module.monitor.State.START, + borgmatic.hooks.monitor.State.START, monitoring_log_level=1, dry_run=False, ) @@ -171,7 +200,7 @@ def test_ping_monitor_with_connection_error_logs_warning(): hook_config = {'topic': topic} flexmock(module.requests).should_receive('post').with_args( f'{default_base_url}/{topic}', - headers=return_default_message_headers(module.monitor.State.FAIL), + headers=return_default_message_headers(borgmatic.hooks.monitor.State.FAIL), auth=None, ).and_raise(module.requests.exceptions.ConnectionError) flexmock(module.logger).should_receive('warning').once() @@ -179,7 +208,7 @@ def test_ping_monitor_with_connection_error_logs_warning(): module.ping_monitor( hook_config, 'config.yaml', - module.monitor.State.FAIL, + borgmatic.hooks.monitor.State.FAIL, monitoring_log_level=1, dry_run=False, ) @@ -193,7 +222,7 @@ def test_ping_monitor_with_other_error_logs_warning(): ) flexmock(module.requests).should_receive('post').with_args( f'{default_base_url}/{topic}', - headers=return_default_message_headers(module.monitor.State.FAIL), + headers=return_default_message_headers(borgmatic.hooks.monitor.State.FAIL), auth=None, ).and_return(response) flexmock(module.logger).should_receive('warning').once() @@ -201,7 +230,7 @@ def test_ping_monitor_with_other_error_logs_warning(): module.ping_monitor( hook_config, 'config.yaml', - module.monitor.State.FAIL, + borgmatic.hooks.monitor.State.FAIL, monitoring_log_level=1, dry_run=False, )