瀏覽代碼

zabbix hook added

Tony Fernandez 9 月之前
父節點
當前提交
b874e7e66f

+ 82 - 0
borgmatic/config/schema.yaml

@@ -1602,6 +1602,88 @@ properties:
                 example:
                     - start
                     - 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:
         type: object
         required: ['services']

+ 2 - 0
borgmatic/hooks/dispatch.py

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

+ 1 - 0
borgmatic/hooks/monitor.py

@@ -9,6 +9,7 @@ MONITOR_HOOK_NAMES = (
     'ntfy',
     'pagerduty',
     '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)
  * [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)
+ * [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
 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
 ```
 
+## 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