ntfy.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import logging
  2. import requests
  3. from borgmatic.hooks import monitor
  4. logger = logging.getLogger(__name__)
  5. MONITOR_STATE_TO_NTFY = {
  6. monitor.State.START: None,
  7. monitor.State.FINISH: None,
  8. monitor.State.FAIL: None,
  9. monitor.State.LOG: None,
  10. }
  11. def initialize_monitor(
  12. ping_url, config_filename, monitoring_log_level, dry_run
  13. ): # pragma: no cover
  14. '''
  15. No initialization is necessary for this monitor.
  16. '''
  17. pass
  18. def ping_monitor(hook_config, config_filename, state, monitoring_log_level, dry_run):
  19. '''
  20. Ping the configured Ntfy topic. Use the given configuration filename in any log entries.
  21. If this is a dry run, then don't actually ping anything.
  22. '''
  23. run_states = hook_config.get('states', ['fail'])
  24. if state.name.lower() in run_states:
  25. dry_run_label = ' (dry run; not actually pinging)' if dry_run else ''
  26. state_config = hook_config.get(
  27. state.name.lower(),
  28. {
  29. 'title': f'A Borgmatic {state.name} event happened',
  30. 'message': f'A Borgmatic {state.name} event happened',
  31. 'priority': 'default',
  32. 'tags': 'borgmatic',
  33. },
  34. )
  35. base_url = hook_config.get('server', 'https://ntfy.sh')
  36. topic = hook_config.get('topic')
  37. logger.info(f'{config_filename}: Pinging ntfy topic {topic}{dry_run_label}')
  38. logger.debug(f'{config_filename}: Using Ntfy ping URL {base_url}/{topic}')
  39. headers = {
  40. 'X-Title': state_config.get('title'),
  41. 'X-Message': state_config.get('message'),
  42. 'X-Priority': state_config.get('priority'),
  43. 'X-Tags': state_config.get('tags'),
  44. }
  45. username = hook_config.get('username')
  46. password = hook_config.get('password')
  47. auth = None
  48. if (username and password) is not None:
  49. auth = requests.auth.HTTPBasicAuth(username, password)
  50. logger.info(f'{config_filename}: Using basic auth with user {username} for ntfy')
  51. elif username is not None:
  52. logger.warning(
  53. f'{config_filename}: Password missing for ntfy authentication, defaulting to no auth'
  54. )
  55. elif password is not None:
  56. logger.warning(
  57. f'{config_filename}: Username missing for ntfy authentication, defaulting to no auth'
  58. )
  59. if not dry_run:
  60. logging.getLogger('urllib3').setLevel(logging.ERROR)
  61. try:
  62. response = requests.post(f'{base_url}/{topic}', headers=headers, auth=auth)
  63. if not response.ok:
  64. response.raise_for_status()
  65. except requests.exceptions.RequestException as error:
  66. logger.warning(f'{config_filename}: ntfy error: {error}')
  67. def destroy_monitor(
  68. ping_url_or_uuid, config_filename, monitoring_log_level, dry_run
  69. ): # pragma: no cover
  70. '''
  71. No destruction is necessary for this monitor.
  72. '''
  73. pass