Browse Source

zabbix hook added

Tony Fernandez 9 months ago
parent
commit
b874e7e66f

+ 82 - 0
borgmatic/config/schema.yaml

@@ -1602,6 +1602,88 @@ properties:
                 example:
                 example:
                     - start
                     - start
                     - finish
                     - finish
+    zabbix:
+        type: object
+        additionalProperties: false
+        properties:
+            itemid:
+                type: integer
+                description: |
+                    The itemid to publish to
+                    for details.
+                example: 55105
+            host:
+                type: string
+                description: |
+                    Host name where the item is stored.
+                    Required if 'itemid' is not set
+                example: borg-server
+            key:
+                type: string
+                description: |
+                    Key of the host where the item is stored.
+                    Required if 'itemid' is not set
+                example: borg.status
+            server:
+                type: string
+                description: |
+                    The address of your self-hosted zabbix instance.
+                example: https://zabbix.your-domain.com
+            username:
+                type: string
+                description: |
+                    The username used for authentication.
+                example: testuser
+            password:
+                type: string
+                description: |
+                    The password used for authentication.
+                example: fakepassword
+            api_key:
+                type: string
+                description: |
+                    The api_key used for authentication.
+                example: fakekey
+            start:
+                type: object
+                properties:
+                    value:
+                        type: string
+                        description: |
+                            The string to set the item value to on start.
+                        example: STARTED
+            finish:
+                type: object
+                properties:
+                    value:
+                        type: string
+                        description: |
+                            The string to set the item value to on finish.
+                        example: FINISH
+            fail:
+                type: object
+                properties:
+                    value:
+                        type: string
+                        description: |
+                            The string to set the item value to on fail.
+                        example: ERROR
+            states:
+                type: array
+                items:
+                    type: string
+                    enum:
+                        - start
+                        - finish
+                        - fail
+                    uniqueItems: true
+                description: |
+                    List of one or more monitoring states to ping for: "start",
+                    "finish", and/or "fail". Defaults to pinging for failure
+                    only.
+                example:
+                    - start
+                    - finish
     apprise:
     apprise:
         type: object
         type: object
         required: ['services']
         required: ['services']

+ 2 - 0
borgmatic/hooks/dispatch.py

@@ -14,6 +14,7 @@ from borgmatic.hooks import (
     postgresql,
     postgresql,
     sqlite,
     sqlite,
     uptimekuma,
     uptimekuma,
+    zabbix,
 )
 )
 
 
 logger = logging.getLogger(__name__)
 logger = logging.getLogger(__name__)
@@ -32,6 +33,7 @@ HOOK_NAME_TO_MODULE = {
     'postgresql_databases': postgresql,
     'postgresql_databases': postgresql,
     'sqlite_databases': sqlite,
     'sqlite_databases': sqlite,
     'uptime_kuma': uptimekuma,
     'uptime_kuma': uptimekuma,
+    'zabbix': zabbix,
 }
 }
 
 
 
 

+ 1 - 0
borgmatic/hooks/monitor.py

@@ -9,6 +9,7 @@ MONITOR_HOOK_NAMES = (
     'ntfy',
     'ntfy',
     'pagerduty',
     'pagerduty',
     'uptime_kuma',
     'uptime_kuma',
+    'zabbix',
 )
 )
 
 
 
 

+ 93 - 0
borgmatic/hooks/zabbix.py

@@ -0,0 +1,93 @@
+import logging
+import requests
+import json
+
+logger = logging.getLogger(__name__)
+
+
+def initialize_monitor(
+    ping_url, config, config_filename, monitoring_log_level, dry_run
+):  # pragma: no cover
+    '''
+    No initialization is necessary for this monitor.
+    '''
+    pass
+
+
+def ping_monitor(hook_config, config, config_filename, state, monitoring_log_level, dry_run):
+    '''
+    Ping the configured Zabbix topic. Use the given configuration filename in any log entries.
+    If this is a dry run, then don't actually ping anything.
+    '''
+
+    run_states = hook_config.get('states', ['fail'])
+
+    if state.name.lower() in run_states:
+        dry_run_label = ' (dry run; not actually pinging)' if dry_run else ''
+
+        state_config = hook_config.get(state.name.lower(),{'value': f'invalid',},)
+
+        base_url = hook_config.get('server', 'https://cloud.zabbix.com/zabbix/api_jsonrpc.php')
+        username = hook_config.get('username')
+        password = hook_config.get('password')
+        api_key = hook_config.get('api_key')
+        itemid = hook_config.get('itemid')
+        host = hook_config.get('host')
+        key = hook_config.get('key')
+
+        value = state_config.get('value')
+
+        headers = {'Content-Type': 'application/json-rpc'}
+
+        logger.info(f'{config_filename}: Pinging zabbix {dry_run_label}')
+        logger.debug(f'{config_filename}: Using zabbix ping URL {base_url}')
+
+        # Determine the zabbix method used to store the value: itemid or host/key
+        if (itemid) is not None:
+            logger.info(f'{config_filename}: Updating {itemid} on zabbix')
+            data = {"jsonrpc":"2.0","method":"history.push","params":{"itemid":itemid,"value":value},"id":1}
+        
+        elif (host and key) is not None:
+            logger.info(f'{config_filename}: Updating Host:{host} and Key:{key} on zabbix')
+            data = {"jsonrpc":"2.0","method":"history.push","params":{"host":host,"key":key,"value":value},"id":1}
+
+        elif (host) is not None:
+            logger.warning( f'{config_filename}: Key missing for zabbix authentication' )
+
+        elif (key) is not None:
+            logger.warning( f'{config_filename}: Host missing for zabbix authentication' )
+
+        # Determine the authentication method: API key or username/password
+        auth = None
+        if (api_key) is not None:
+            logger.info(f'{config_filename}: Using API key auth for zabbix')
+            headers['Authorization'] = 'Bearer ' + api_key
+            
+        elif (username and password) is not None:
+            logger.info(f'{config_filename}: Using user/pass auth with user {username} for zabbix')
+            response = requests.post(base_url, headers=headers, data='{"jsonrpc":"2.0","method":"user.login","params":{"username":"'+username+'","password":"'+password+'"},"id":1}')
+            data['auth'] = response.json().get('result')
+
+        elif username is not None:
+            logger.warning( f'{config_filename}: Password missing for zabbix authentication, defaulting to no auth' )
+
+        elif password is not None:
+            logger.warning( f'{config_filename}: Username missing for zabbix authentication, defaulting to no auth' )
+
+        if not dry_run:
+            logging.getLogger('urllib3').setLevel(logging.ERROR)
+            try:
+                response = requests.post(base_url, headers=headers, data=json.dumps(data))
+                if not response.ok:
+                    response.raise_for_status()
+            except requests.exceptions.RequestException as error:
+                logger.warning(f'{config_filename}: zabbix error: {error}')
+
+
+def destroy_monitor(
+    ping_url_or_uuid, config, config_filename, monitoring_log_level, dry_run
+):  # pragma: no cover
+    '''
+    No destruction is necessary for this monitor.
+    '''
+    pass

+ 50 - 0
docs/how-to/monitor-your-backups.md

@@ -47,6 +47,7 @@ them as backups happen:
  * [ntfy](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#ntfy-hook)
  * [ntfy](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#ntfy-hook)
  * [PagerDuty](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#pagerduty-hook)
  * [PagerDuty](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#pagerduty-hook)
  * [Uptime Kuma](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#uptime-kuma-hook)
  * [Uptime Kuma](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#uptime-kuma-hook)
+ * [Zabbix](https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#zabbix-hook)
 
 
 The idea is that you'll receive an alert when something goes wrong or when the
 The idea is that you'll receive an alert when something goes wrong or when the
 service doesn't hear from borgmatic for a configured interval (if supported).
 service doesn't hear from borgmatic for a configured interval (if supported).
@@ -562,6 +563,55 @@ Heartbeat Retry = 360          # = 10 minutes
 Resend Notification every X times = 1
 Resend Notification every X times = 1
 ```
 ```
 
 
+## zabbix hook
+
+<span class="minilink minilink-addedin">New in version 1.8.15</span>
+[zabbix](https://www.zabbix.com/) is an open-source monitoring tool used for tracking and managing the performance and availability of networks, servers, and applications in real-time.
+
+This hook does not do any notifications on it's own. Instead, it relies on
+your zabbix instance to notify and perform escalations based on the zabbix
+configuration. The `states` list will choose which states to trigger on. 
+Each state can have its own custom values configured. These values are 
+populated in the item data in zabbix. If none are provided, will use the
+default.
+
+An example configuration is shown here with all the available options.
+
+```yaml
+zabbix:
+    server: http://cloud.zabbix.com/zabbix/api_jsonrpc.php
+    
+    username: myuser
+    password: secret
+    api_key: b2ecba64d8beb47fc161ae48b164cfd7104a79e8e48e6074ef5b141d8a0aeeca
+
+    host: "borg-server"
+    key: borg.status
+    itemid: 55105
+
+    start:
+        value: "STARTED"
+    finish:
+        value: "OK"
+    fail:
+        value: "ERROR"
+    states:
+        - start
+        - finish
+        - fail
+```
+
+<span class="minilink minilink-addedin">Authentication Methods</span>
+Authentication can be accomplished via `api_key` or `username` and `password`. 
+If both are declared, `api_key` will be chosen.
+
+<span class="minilink minilink-addedin">Items</span> The item 
+to be updated can be chosen by either declaring the `itemid` or 
+`host` and `key`. If both are declared, `itemid` will be chosen.
+
+Keep in mind that `host` the Host name on the host and not the 
+Visual name.
+
 
 
 ## Scripting borgmatic
 ## Scripting borgmatic