From 129f3e753c948b0315208c614e6bfdf063fab9e4 Mon Sep 17 00:00:00 2001 From: Dan Helfman Date: Tue, 29 Oct 2024 10:33:19 -0700 Subject: [PATCH] Flesh out the Zabbix monitoring hook tests, add a logo to the documentation, etc. --- NEWS | 2 + README.md | 1 + borgmatic/config/schema.yaml | 15 +- borgmatic/hooks/zabbix.py | 32 ++- docs/how-to/monitor-your-backups.md | 37 ++-- docs/static/zabbix.png | Bin 0 -> 8572 bytes tests/unit/hooks/test_zabbix.py | 322 ++++++++++++++++++++-------- 7 files changed, 281 insertions(+), 128 deletions(-) create mode 100644 docs/static/zabbix.png diff --git a/NEWS b/NEWS index 442f4e6c..f7ff6b92 100644 --- a/NEWS +++ b/NEWS @@ -30,6 +30,8 @@ * Update the "--match-archives" and "--archive" flags to support Borg 2 series names or archive hashes. * Add a "--match-archives" flag to the "prune" action. + * Add a Zabbix monitoring hook. See the documentation for more information: + https://torsion.org/borgmatic/docs/how-to/monitor-your-backups/#zabbix-hook 1.8.14 * #896: Fix an error in borgmatic rcreate/init on an empty repository directory with Borg 1.4. diff --git a/README.md b/README.md index a7000d68..45b48a4e 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ borgmatic is powered by [Borg Backup](https://www.borgbackup.org/). ntfy Loki Apprise +Zabbix BorgBase diff --git a/borgmatic/config/schema.yaml b/borgmatic/config/schema.yaml index 9536164a..4dd7c76f 100644 --- a/borgmatic/config/schema.yaml +++ b/borgmatic/config/schema.yaml @@ -1622,12 +1622,14 @@ properties: host: type: string description: | - Host name where the item is stored. Required if "itemid" is not set. + 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. + Key of the host where the item is stored. Required if + "itemid" is not set. example: borg.status server: type: string @@ -1637,17 +1639,20 @@ properties: username: type: string description: | - The username used for authentication. Not needed if using an API key. + The username used for authentication. Not needed if using + an API key. example: testuser password: type: string description: | - The password used for authentication. Not needed if using an API key. + The password used for authentication. Not needed if using + an API key. example: fakepassword api_key: type: string description: | - The API key used for authentication. Not needed if using an username/password. + The API key used for authentication. Not needed if using + an username/password. example: fakekey start: type: object diff --git a/borgmatic/hooks/zabbix.py b/borgmatic/hooks/zabbix.py index 13f51b64..a33d77b4 100644 --- a/borgmatic/hooks/zabbix.py +++ b/borgmatic/hooks/zabbix.py @@ -1,4 +1,3 @@ -import json import logging import requests @@ -52,23 +51,23 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev logger.warning(f'{config_filename}: Server missing for Zabbix') return - # Determine the zabbix method used to store the value: itemid or host/key + # 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, + '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, + 'jsonrpc': '2.0', + 'method': 'history.push', + 'params': {'host': host, 'key': key, 'value': value}, + 'id': 1, } elif host is not None: @@ -90,13 +89,10 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev elif (username and password) is not None: logger.info(f'{config_filename}: Using user/pass auth with user {username} for Zabbix') auth_data = { - "jsonrpc": "2.0", - "method": "user.login", - "params": { - "username": username, - "password": password - }, - "id": 1 + 'jsonrpc': '2.0', + 'method': 'user.login', + 'params': {'username': username, 'password': password}, + 'id': 1, } if not dry_run: logging.getLogger('urllib3').setLevel(logging.ERROR) @@ -107,6 +103,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev response.raise_for_status() except requests.exceptions.RequestException as error: logger.warning(f'{config_filename}: Zabbix error: {error}') + return elif username is not None: logger.warning(f'{config_filename}: Password missing for Zabbix authentication') @@ -118,7 +115,6 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev else: logger.warning(f'{config_filename}: Authentication data missing for Zabbix') return - if not dry_run: logging.getLogger('urllib3').setLevel(logging.ERROR) diff --git a/docs/how-to/monitor-your-backups.md b/docs/how-to/monitor-your-backups.md index 3ea51735..f5007401 100644 --- a/docs/how-to/monitor-your-backups.md +++ b/docs/how-to/monitor-your-backups.md @@ -566,14 +566,16 @@ Resend Notification every X times = 1 ## Zabbix hook New in version 1.9.0 -[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. +[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 its own. Instead, it relies on -your Zabbix instance to notify and perform escalations based on the Zabbix -configuration. The `states` defined in the configuration will determine which states -will trigger the hook. The value defined in the configuration of each state is -used to populate the data of the configured Zabbix item. If none are provided, -it default to a lower-case string of the state. +This hook does not do any notifications on its own. Instead, it relies on your +Zabbix instance to notify and perform escalations based on the Zabbix +configuration. The `states` defined in the configuration determine which +states will trigger the hook. The value defined in the configuration of each +state is used to populate the data of the configured Zabbix item. If none are +provided, it defaults to a lower-case string of the state. An example configuration is shown here with all the available options. @@ -601,19 +603,22 @@ zabbix: - fail ``` -### Zabbix 7.0+ This hook requires the Zabbix server be running version 7.0+ -Authentication Methods -Authentication can be accomplished via `api_key` or `username` and `password`. -If both are declared, `api_key` will be chosen. -Items 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. +### Authentication methods -Keep in mind that `host` is referring to the 'Host name' on the -Zabbix host and not the 'Visual name'. +Authentication can be accomplished via `api_key` or both `username` and +`password`. If all three are declared, only `api_key` is used. + + +### Items + +The item to be updated can be chosen by either declaring the `itemid` or both +`host` and `key`. If all three are declared, only `itemid` is used. + +Keep in mind that `host` is referring to the "Host name" on the Zabbix server +and not the "Visual name". ## Scripting borgmatic diff --git a/docs/static/zabbix.png b/docs/static/zabbix.png new file mode 100644 index 0000000000000000000000000000000000000000..746ad2bcf5c99e83162078a07f36a40e1283e193 GIT binary patch literal 8572 zcmZ`;byQT*x29o`F6nM0q(o|np}Pc>mX_}BAq1pTN>JJX36X9oY3Y{kW~hO8`K|ZQ zTkpL!Yi8YZ?z#8QJ$vtOfBV}pn(7L;*p%2vNJzL!iV$riB;-Wk*bWN=_$ATvECVLO z?PO&&m1Jeuim2?e6rElbtCvSZeM zSTlm8QzDsrd$nA+MXrAsc)GYwPj%`Mpn;`wXmUu5zxF(SgOa_ZrG~FBwe~HENtI?~ zIeGUYExA9Q@-;{H@brV-2Z`Mc@*#aJ?jUYbDq&Y6W6JmDD$;QGT`*6p6{%*-R+s| zAyj+CZrU$sxZcuh$g6L-pLY*k%lT3B$1|Hr(Tq?fkwIFHlqGeIUb#a0V?4=WU*LUr zo+)dFGK`4)HJN58UhjGMW9PBc;r(Ar0S;=+CQ~E$dz_s)bV{KagrwKfZxBHM1}yGp zyEdjZSgESMzMpWc9oNXHLC6#T*CKLco@%eQIESK6|8^)`;I{Y$pU<<1>Fn0}E7x13 zuVob*xGpYOanITPm$sK$b6XMq#ZxQz@t1Btwi^EJ09L`UP*H#&JwAO3T1!%Z8IX&j zp*vu}nWrzZ4EtvvU=q_qNlgxO2b+eFgl{P2BM}l3ou3j!TGwa(FxS^dcj~6Ez1A|_ z^5?-oM1&ejbO;8i?Kj&cq?eU3>Qh1uC~%(1sSr{jvgmq$CN-XN>AvZ*oE8suf@Nu@=9y;R`RZ<3mow@zu zs+%|E9fuM!6ouM*32+lZ%&SyM-|p-zwYZ1gFv^L$73Gn)4usK|&< zT}QuAlQhITecMlbG#~!zND||RG*&~RT+b|Pe2kdI*`g>uy)V#)AIA1m2#h(dNM4Bg zla0G?NfDBgw!mU`Y{^;GAsM(-W6hN~pbs-L?vrZLrw3|}x6kcY0yC~8ic7lrTrH&Z z?Y6v^*U0dZriL=Qn}XY&t48JVUCjqawh*r(UDs!^lQ0=#VxkRy5e$@QFp0j(XfRVz zHx;7Htf?70??7gDnnTg6GD!~JI?EDRWBxUY)N%itO7nLQ+J@x%*;&EfTuN>3`i7FO z(`VUBak{1L5^eYM7W>SAze0O}W`DB96sjLaIa3Vp(W9KL4 zkl{Ss{%>LdzxMYulXG!>T5}vpwX~w|7FO(B(v-^y~o_}YqiWz$>91h!A#Doda}R4 zYCcSvykE}Ai$BfVwv%&bmLIOj8q7%=hc7w%Ff|l{EWO@+L~_SP5*>W02a&vC7Wh57 zBOfO4FA1x>ezhFJFFMZ)Cv9+`kilXbJ?Km5PX4^$EAv|tm6EnXs9@$* z9No&A+R};FK|UYs+9iVr${>+T@z16!5?>($zMOJ!e(Gw)QB*|O;9$7@48G*e6fiG1 z;$_l6#bRif`>(0#;!oRk(qN-I!z)U;sh6sThFCPBsnfIja-cP+=N{tL?BtcTWr4-j zf%>6luJqx2eW@?v67L0_W#VU5z}YlC_c8R2mo?$L;bZ3A^fUIpkLfpu4deGKk6pe; zMp6fBFF0k!f4S0pe!b@*rHCc-XN%0AnN3#A5{u(ut$aZ3EoB#7Aj$LPpm)iPZsTcI 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 PV;)IKP8|Z1F$?=IE