[packages/nagios-plugin-check_json_health] Initial (PLD is "upstream" for it)
arekm
arekm at pld-linux.org
Mon Mar 30 23:43:06 CEST 2026
commit 3bf64a96bc7c3d3a4c08c58803e497674dddc659
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date: Mon Mar 30 23:41:47 2026 +0200
Initial (PLD is "upstream" for it)
check_json_health.cfg | 29 ++++++++
check_json_health.py | 132 +++++++++++++++++++++++++++++++++++
nagios-plugin-check_json_health.spec | 41 +++++++++++
3 files changed, 202 insertions(+)
---
diff --git a/nagios-plugin-check_json_health.spec b/nagios-plugin-check_json_health.spec
new file mode 100644
index 0000000..1a919f6
--- /dev/null
+++ b/nagios-plugin-check_json_health.spec
@@ -0,0 +1,41 @@
+%define plugin check_json_health
+Summary: Nagios plugin to check JSON health endpoints
+Name: nagios-plugin-%{plugin}
+Version: 1.0
+Release: 1
+License: Public Domain (CC0 1.0)
+Group: Networking
+Source0: %{plugin}.py
+Source1: %{plugin}.cfg
+URL: https://github.com/pld-linux
+Requires: python3
+Requires: python3-modules
+BuildArch: noarch
+BuildRoot: %{tmpdir}/%{name}-%{version}-root-%(id -u -n)
+
+%define _sysconfdir /etc/nagios/plugins
+%define plugindir %{_prefix}/lib/nagios/plugins
+
+%description
+Generic Nagios plugin for checking HTTP(S) endpoints that return JSON
+with standard health fields (exit_code, status, message). The server
+owns all threshold logic; the plugin simply fetches, extracts, and
+forwards the status to Nagios.
+
+%prep
+%setup -q -c -T
+cp -p %{SOURCE0} %{plugin}
+
+%install
+rm -rf $RPM_BUILD_ROOT
+install -d $RPM_BUILD_ROOT{%{_sysconfdir},%{plugindir}}
+install -p %{plugin} $RPM_BUILD_ROOT%{plugindir}/%{plugin}
+cp -p %{SOURCE1} $RPM_BUILD_ROOT%{_sysconfdir}/%{plugin}.cfg
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(644,root,root,755)
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/%{plugin}.cfg
+%attr(755,root,root) %{plugindir}/%{plugin}
diff --git a/check_json_health.cfg b/check_json_health.cfg
new file mode 100644
index 0000000..6ec6221
--- /dev/null
+++ b/check_json_health.cfg
@@ -0,0 +1,29 @@
+define command {
+ command_name check_json_health
+ command_line $USER1$/check_json_health -H $HOSTADDRESS$ -p $ARG1$ -u $ARG2$ $ARG3$
+}
+
+# Example service definitions:
+#
+# define service {
+# use generic-service
+# host_name myapp.example.com
+# service_description JSON Health Check
+# check_command check_json_health!443!/health!
+# }
+#
+# With perfdata and insecure SSL:
+# define service {
+# use generic-service
+# host_name myapp.example.com
+# service_description JSON Health Check
+# check_command check_json_health!443!/nagios/!-k --perfdata-field details
+# }
+#
+# Plain HTTP:
+# define service {
+# use generic-service
+# host_name myapp.example.com
+# service_description JSON Health Check
+# check_command check_json_health!8080!/health!--no-ssl
+# }
diff --git a/check_json_health.py b/check_json_health.py
new file mode 100644
index 0000000..11833c3
--- /dev/null
+++ b/check_json_health.py
@@ -0,0 +1,132 @@
+#!/usr/bin/python3
+#
+# This work is dedicated to the public domain under CC0 1.0.
+# https://creativecommons.org/publicdomain/zero/1.0/
+#
+# To the extent possible under law, the author(s) have dedicated all
+# copyright and related and neighboring rights to this software to the
+# public domain worldwide. This software is distributed without any warranty.
+#
+"""
+check_json_health - Generic Nagios plugin for JSON health endpoints.
+
+Checks any HTTP(S) URL that returns JSON with standard health fields:
+ - exit_code: Nagios exit code (0=OK, 1=WARNING, 2=CRITICAL, 3=UNKNOWN)
+ - status: Status keyword (OK, WARNING, CRITICAL, UNKNOWN)
+ - message: Human-readable status message
+
+The server owns all threshold logic. This plugin simply fetches,
+extracts, and forwards the status to Nagios.
+
+Dependencies: Python 3 stdlib only (no pip packages).
+
+Installation:
+ cp check_json_health /usr/lib/nagios/plugins/
+ chmod +x /usr/lib/nagios/plugins/check_json_health
+
+Usage:
+ check_json_health -H <hostname> [-p <port>] [-u <uri>] [-t <timeout>]
+ check_json_health -H k-gw-prod.example.com -u /nagios/ --perfdata-field details
+ check_json_health -H myapp.example.com -u /health -k --no-ssl -p 8080
+"""
+
+import argparse
+import json
+import ssl
+import sys
+import urllib.request
+
+OK, WARNING, CRITICAL, UNKNOWN = 0, 1, 2, 3
+
+
+def sanitize(s):
+ """Remove characters that could break Nagios output parsing.
+
+ Strips pipe (perfdata separator), newlines (Nagios reads first line only),
+ and carriage returns from values originating in the JSON response.
+ """
+ return str(s).replace('|', '/').replace('\n', ' ').replace('\r', '')
+
+
+def main():
+ parser = argparse.ArgumentParser(
+ description='Nagios plugin: check a JSON health endpoint')
+ parser.add_argument('-H', '--hostname', required=True,
+ help='Server hostname or IP')
+ parser.add_argument('-p', '--port', type=int, default=443,
+ help='Port (default: 443)')
+ parser.add_argument('-u', '--uri', default='/nagios/',
+ help='URI path (default: /nagios/)')
+ parser.add_argument('--no-ssl', action='store_true', default=False,
+ help='Use plain HTTP instead of HTTPS (default: HTTPS)')
+ parser.add_argument('-k', '--insecure', action='store_true',
+ help='Skip SSL certificate verification')
+ parser.add_argument('-t', '--timeout', type=int, default=15,
+ help='Connection timeout in seconds (default: 15)')
+ parser.add_argument('--status-field', default='status',
+ help='JSON field for status keyword (default: status)')
+ parser.add_argument('--exit-code-field', default='exit_code',
+ help='JSON field for exit code (default: exit_code)')
+ parser.add_argument('--message-field', default='message',
+ help='JSON field for message (default: message)')
+ parser.add_argument('--perfdata-field', default=None,
+ help='JSON field for perfdata - dict of key:number '
+ 'or pre-formatted string (default: none)')
+ args = parser.parse_args()
+
+ scheme = 'http' if args.no_ssl else 'https'
+ url = f'{scheme}://{args.hostname}:{args.port}{args.uri}'
+
+ try:
+ if args.no_ssl:
+ ctx = None
+ else:
+ ctx = ssl.create_default_context()
+ if args.insecure:
+ ctx.check_hostname = False
+ ctx.verify_mode = ssl.CERT_NONE
+
+ req = urllib.request.Request(url, headers={'Cache-Control': 'no-cache'})
+ with urllib.request.urlopen(req, timeout=args.timeout, context=ctx) as resp:
+ body = resp.read().decode('utf-8')
+ except Exception as e:
+ # Connectivity/infrastructure failure = UNKNOWN (service state is indeterminate)
+ print(f'UNKNOWN - {url}: {e}')
+ sys.exit(UNKNOWN)
+
+ try:
+ data = json.loads(body)
+
+ exit_code = int(data.get(args.exit_code_field, UNKNOWN))
+ if exit_code not in (OK, WARNING, CRITICAL, UNKNOWN):
+ exit_code = UNKNOWN
+
+ status = sanitize(data.get(args.status_field, 'UNKNOWN'))
+ message = sanitize(data.get(args.message_field, 'No message in response'))
+
+ output = f'{status} - {message}'
+
+ # Optional perfdata from a JSON field
+ if args.perfdata_field:
+ perfdata_raw = data.get(args.perfdata_field)
+ if isinstance(perfdata_raw, dict):
+ pairs = ' '.join(
+ f'{sanitize(k)}={v}'
+ for k, v in perfdata_raw.items()
+ if isinstance(v, (int, float))
+ )
+ if pairs:
+ output += f' | {pairs}'
+ elif isinstance(perfdata_raw, str) and perfdata_raw:
+ output += f' | {sanitize(perfdata_raw)}'
+
+ print(output)
+ sys.exit(exit_code)
+ except Exception as e:
+ # JSON parse or field extraction failure = CRITICAL (service returned garbage)
+ print(f'CRITICAL - {url}: {e}')
+ sys.exit(CRITICAL)
+
+
+if __name__ == '__main__':
+ main()
================================================================
---- gitweb:
http://git.pld-linux.org/gitweb.cgi/packages/nagios-plugin-check_json_health.git/commitdiff/3bf64a96bc7c3d3a4c08c58803e497674dddc659
More information about the pld-cvs-commit
mailing list