Browse Source

feat: add verify_tls flag for Healthchecks

Uli 2 years ago
parent
commit
5c6407047f

+ 6 - 0
borgmatic/config/schema.yaml

@@ -1012,6 +1012,12 @@ properties:
                             Healthchecks ping URL or UUID to notify when a
                             Healthchecks ping URL or UUID to notify when a
                             backup begins, ends, or errors.
                             backup begins, ends, or errors.
                         example: https://hc-ping.com/your-uuid-here
                         example: https://hc-ping.com/your-uuid-here
+                    verify_tls:
+                        type: boolean
+                        description: |
+                            Verify the SSL certificate of the endpoint.
+                            Defaults to true.
+                        example: false
                     send_logs:
                     send_logs:
                         type: boolean
                         type: boolean
                         description: |
                         description: |

+ 3 - 1
borgmatic/hooks/healthchecks.py

@@ -125,7 +125,9 @@ def ping_monitor(hook_config, config_filename, state, monitoring_log_level, dry_
     if not dry_run:
     if not dry_run:
         logging.getLogger('urllib3').setLevel(logging.ERROR)
         logging.getLogger('urllib3').setLevel(logging.ERROR)
         try:
         try:
-            response = requests.post(ping_url, data=payload.encode('utf-8'))
+            response = requests.post(
+                ping_url, data=payload.encode('utf-8'), verify=hook_config.get('verify_tls', True)
+            )
             if not response.ok:
             if not response.ok:
                 response.raise_for_status()
                 response.raise_for_status()
         except requests.exceptions.RequestException as error:
         except requests.exceptions.RequestException as error:

+ 43 - 7
tests/unit/hooks/test_healthchecks.py

@@ -138,7 +138,7 @@ def test_ping_monitor_hits_ping_url_for_start_state():
     flexmock(module).should_receive('Forgetful_buffering_handler')
     flexmock(module).should_receive('Forgetful_buffering_handler')
     hook_config = {'ping_url': 'https://example.com'}
     hook_config = {'ping_url': 'https://example.com'}
     flexmock(module.requests).should_receive('post').with_args(
     flexmock(module.requests).should_receive('post').with_args(
-        'https://example.com/start', data=''.encode('utf-8')
+        'https://example.com/start', data=''.encode('utf-8'), verify=True
     ).and_return(flexmock(ok=True))
     ).and_return(flexmock(ok=True))
 
 
     module.ping_monitor(
     module.ping_monitor(
@@ -155,7 +155,7 @@ def test_ping_monitor_hits_ping_url_for_finish_state():
     payload = 'data'
     payload = 'data'
     flexmock(module).should_receive('format_buffered_logs_for_payload').and_return(payload)
     flexmock(module).should_receive('format_buffered_logs_for_payload').and_return(payload)
     flexmock(module.requests).should_receive('post').with_args(
     flexmock(module.requests).should_receive('post').with_args(
-        'https://example.com', data=payload.encode('utf-8')
+        'https://example.com', data=payload.encode('utf-8'), verify=True
     ).and_return(flexmock(ok=True))
     ).and_return(flexmock(ok=True))
 
 
     module.ping_monitor(
     module.ping_monitor(
@@ -172,7 +172,7 @@ def test_ping_monitor_hits_ping_url_for_fail_state():
     payload = 'data'
     payload = 'data'
     flexmock(module).should_receive('format_buffered_logs_for_payload').and_return(payload)
     flexmock(module).should_receive('format_buffered_logs_for_payload').and_return(payload)
     flexmock(module.requests).should_receive('post').with_args(
     flexmock(module.requests).should_receive('post').with_args(
-        'https://example.com/fail', data=payload.encode('utf')
+        'https://example.com/fail', data=payload.encode('utf'), verify=True
     ).and_return(flexmock(ok=True))
     ).and_return(flexmock(ok=True))
 
 
     module.ping_monitor(
     module.ping_monitor(
@@ -189,7 +189,43 @@ def test_ping_monitor_with_ping_uuid_hits_corresponding_url():
     payload = 'data'
     payload = 'data'
     flexmock(module).should_receive('format_buffered_logs_for_payload').and_return(payload)
     flexmock(module).should_receive('format_buffered_logs_for_payload').and_return(payload)
     flexmock(module.requests).should_receive('post').with_args(
     flexmock(module.requests).should_receive('post').with_args(
-        'https://hc-ping.com/{}'.format(hook_config['ping_url']), data=payload.encode('utf-8')
+        'https://hc-ping.com/{}'.format(hook_config['ping_url']),
+        data=payload.encode('utf-8'),
+        verify=True,
+    ).and_return(flexmock(ok=True))
+
+    module.ping_monitor(
+        hook_config,
+        'config.yaml',
+        state=module.monitor.State.FINISH,
+        monitoring_log_level=1,
+        dry_run=False,
+    )
+
+
+def test_ping_monitor_skips_ssl_verification_when_verify_tls_false():
+    hook_config = {'ping_url': 'https://example.com', 'verify_tls': False}
+    payload = 'data'
+    flexmock(module).should_receive('format_buffered_logs_for_payload').and_return(payload)
+    flexmock(module.requests).should_receive('post').with_args(
+        'https://example.com', data=payload.encode('utf-8'), verify=False
+    ).and_return(flexmock(ok=True))
+
+    module.ping_monitor(
+        hook_config,
+        'config.yaml',
+        state=module.monitor.State.FINISH,
+        monitoring_log_level=1,
+        dry_run=False,
+    )
+
+
+def test_ping_monitor_executes_ssl_verification_when_verify_tls_true():
+    hook_config = {'ping_url': 'https://example.com', 'verify_tls': True}
+    payload = 'data'
+    flexmock(module).should_receive('format_buffered_logs_for_payload').and_return(payload)
+    flexmock(module.requests).should_receive('post').with_args(
+        'https://example.com', data=payload.encode('utf-8'), verify=True
     ).and_return(flexmock(ok=True))
     ).and_return(flexmock(ok=True))
 
 
     module.ping_monitor(
     module.ping_monitor(
@@ -233,7 +269,7 @@ def test_ping_monitor_hits_ping_url_when_states_matching():
     flexmock(module).should_receive('Forgetful_buffering_handler')
     flexmock(module).should_receive('Forgetful_buffering_handler')
     hook_config = {'ping_url': 'https://example.com', 'states': ['start', 'finish']}
     hook_config = {'ping_url': 'https://example.com', 'states': ['start', 'finish']}
     flexmock(module.requests).should_receive('post').with_args(
     flexmock(module.requests).should_receive('post').with_args(
-        'https://example.com/start', data=''.encode('utf-8')
+        'https://example.com/start', data=''.encode('utf-8'), verify=True
     ).and_return(flexmock(ok=True))
     ).and_return(flexmock(ok=True))
 
 
     module.ping_monitor(
     module.ping_monitor(
@@ -249,7 +285,7 @@ def test_ping_monitor_with_connection_error_logs_warning():
     flexmock(module).should_receive('Forgetful_buffering_handler')
     flexmock(module).should_receive('Forgetful_buffering_handler')
     hook_config = {'ping_url': 'https://example.com'}
     hook_config = {'ping_url': 'https://example.com'}
     flexmock(module.requests).should_receive('post').with_args(
     flexmock(module.requests).should_receive('post').with_args(
-        'https://example.com/start', data=''.encode('utf-8')
+        'https://example.com/start', data=''.encode('utf-8'), verify=True
     ).and_raise(module.requests.exceptions.ConnectionError)
     ).and_raise(module.requests.exceptions.ConnectionError)
     flexmock(module.logger).should_receive('warning').once()
     flexmock(module.logger).should_receive('warning').once()
 
 
@@ -270,7 +306,7 @@ def test_ping_monitor_with_other_error_logs_warning():
         module.requests.exceptions.RequestException
         module.requests.exceptions.RequestException
     )
     )
     flexmock(module.requests).should_receive('post').with_args(
     flexmock(module.requests).should_receive('post').with_args(
-        'https://example.com/start', data=''.encode('utf-8')
+        'https://example.com/start', data=''.encode('utf-8'), verify=True
     ).and_return(response)
     ).and_return(response)
     flexmock(module.logger).should_receive('warning').once()
     flexmock(module.logger).should_receive('warning').once()