Hello community, here is the log from the commit of package monitoring-plugins-http_json for openSUSE:Factory checked in at 2020-07-05 01:19:47 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/monitoring-plugins-http_json (Old) and /work/SRC/openSUSE:Factory/.monitoring-plugins-http_json.new.3060 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "monitoring-plugins-http_json" Sun Jul 5 01:19:47 2020 rev:2 rq:818546 version:2.1+git.1593763135.c23ebac Changes: -------- --- /work/SRC/openSUSE:Factory/monitoring-plugins-http_json/monitoring-plugins-http_json.changes 2020-04-01 19:19:36.971565612 +0200 +++ /work/SRC/openSUSE:Factory/.monitoring-plugins-http_json.new.3060/monitoring-plugins-http_json.changes 2020-07-05 01:21:32.197617216 +0200 @@ -1,0 +2,15 @@ +Fri Jul 03 08:11:34 UTC 2020 - mli...@suse.cz + +- Update to version 2.1+git.1593763135.c23ebac: + * Add JSON parsing on HTTPError + * Add handling of empty JSON return values + * Add spaces to debug output + * Add JSON parsing on HTTPError + * Adjust pylint for new function + * Move main entrypoint to own function for simpler testing + * Add Makefile and requirements.txt for easier testing + * Update README + * added missing cli args for V2.0 + * added icinga2 command definitions + +------------------------------------------------------------------- Old: ---- monitoring-plugins-http_json-2.0+git.1585671306.219e993.tar.xz New: ---- monitoring-plugins-http_json-2.1+git.1593763135.c23ebac.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ monitoring-plugins-http_json.spec ++++++ --- /var/tmp/diff_new_pack.vFecRW/_old 2020-07-05 01:21:34.245623163 +0200 +++ /var/tmp/diff_new_pack.vFecRW/_new 2020-07-05 01:21:34.245623163 +0200 @@ -20,7 +20,7 @@ %define skip_python2 1 %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: monitoring-plugins-http_json -Version: 2.0+git.1585671306.219e993 +Version: 2.1+git.1593763135.c23ebac Release: 0 Summary: Plugin for Nagios which checks json values from a given HTTP endpoint License: Apache-2.0 @@ -30,8 +30,8 @@ Source1: https://raw.githubusercontent.com/bb-Ricardo/nagios-http-json/next-release/contrib/icinga2_check_command_definition.conf BuildRequires: %{python_module setuptools} BuildRequires: fdupes -BuildRequires: python-rpm-macros BuildRequires: nagios-rpm-macros +BuildRequires: python-rpm-macros BuildArch: noarch %python_subpackages ++++++ _service ++++++ --- /var/tmp/diff_new_pack.vFecRW/_old 2020-07-05 01:21:34.273623243 +0200 +++ /var/tmp/diff_new_pack.vFecRW/_new 2020-07-05 01:21:34.277623256 +0200 @@ -1,12 +1,11 @@ <services> <service name="tar_scm" mode="disabled"> - <param name="versionprefix">2.0+git</param> + <param name="versionprefix">2.1+git</param> <param name="url">https://github.com/drewkerrigan/nagios-http-json.git</param> <param name="filename">monitoring-plugins-http_json</param> <param name="scm">git</param> <param name="exclude">.git*</param> <param name="changesgenerate">enable</param> - <param name="changesauthor">mc...@cepl.eu</param> </service> <service name="recompress" mode="disabled"> <param name="compression">xz</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.vFecRW/_old 2020-07-05 01:21:34.293623302 +0200 +++ /var/tmp/diff_new_pack.vFecRW/_new 2020-07-05 01:21:34.293623302 +0200 @@ -1,4 +1,4 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/drewkerrigan/nagios-http-json.git</param> - <param name="changesrevision">0cbbf41b9ca50df9d9eb0d0db7a95b7a1a5ec811</param></service></servicedata> \ No newline at end of file + <param name="changesrevision">47a37556ba96b322b8a4c95b482034eb80a8ec95</param></service></servicedata> \ No newline at end of file ++++++ icinga2_check_command_definition.conf ++++++ --- /var/tmp/diff_new_pack.vFecRW/_old 2020-07-05 01:21:34.317623371 +0200 +++ /var/tmp/diff_new_pack.vFecRW/_new 2020-07-05 01:21:34.317623371 +0200 @@ -1,9 +1,9 @@ object CheckCommand "http_json" { - import "plugin-check-command" + import "plugin-check-command" - command = [ PluginDir + "/check_http_json.py" ] + command = [ PluginDir + "/check_http_json.py" ] - arguments = { + arguments = { "--host" = { value = "$address$" description = "Hostname or address of the interface to query" @@ -53,12 +53,14 @@ value = "$http_json_headers$" description = "additional http headers in JSON format to send with the request" } - "--field_separator" = { value = "$http_json_field_separator$" description = "JSON Field separator, defaults to '.'; Select element in an array with '(' ')'" } - + "--value_separator" = { + value = "$http_json_value_separator$" + description = "JSON Value separator, defaults to ':'" + } "--warning" = { value = "$http_json_warning$" description = "Warning threshold for these values, WarningRange is in the format [@]start:end" ++++++ monitoring-plugins-http_json-2.0+git.1585671306.219e993.tar.xz -> monitoring-plugins-http_json-2.1+git.1593763135.c23ebac.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/.pylintrc new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/.pylintrc --- old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/.pylintrc 2020-03-31 18:15:06.000000000 +0200 +++ new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/.pylintrc 2020-07-03 09:58:55.000000000 +0200 @@ -1,5 +1,5 @@ # pylint config [MESSAGES CONTROL] -disable=line-too-long, redefined-outer-name, too-many-arguments, too-many-instance-attributes, fixme, invalid-name, superfluous-parens, missing-function-docstring, missing-module-docstring, multiple-imports, no-else-return, too-many-return-statements +disable=line-too-long, redefined-outer-name, too-many-arguments, too-many-instance-attributes, fixme, invalid-name, superfluous-parens, missing-function-docstring, missing-module-docstring, multiple-imports, no-else-return, too-many-return-statements, too-many-branches, too-many-statements [MASTER] ignore-patterns=^test.* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/README.md new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/README.md --- old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/README.md 2020-03-31 18:15:06.000000000 +0200 +++ new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/README.md 2020-07-03 09:58:55.000000000 +0200 @@ -20,7 +20,7 @@ usage: check_http_json.py [-h] [-d] [-s] -H HOST [-k] [-V] [--cacert CACERT] [--cert CERT] [--key KEY] [-P PORT] [-p PATH] [-t TIMEOUT] [-B AUTH] [-D DATA] [-A HEADERS] - [-f SEPARATOR] + [-f FIELD_SEPARATOR] [-F VALUE_SEPARATOR] [-w [KEY_THRESHOLD_WARNING [KEY_THRESHOLD_WARNING ...]]] [-c [KEY_THRESHOLD_CRITICAL [KEY_THRESHOLD_CRITICAL ...]]] [-e [KEY_LIST [KEY_LIST ...]]] @@ -62,6 +62,8 @@ -f SEPARATOR, --field_separator SEPARATOR JSON Field separator, defaults to "."; Select element in an array with "(" ")" + -F SEPARATOR, --value_separator SEPARATOR + JSON Value separator, defaults to ":"; -w [KEY_THRESHOLD_WARNING [KEY_THRESHOLD_WARNING ...]], --warning [KEY_THRESHOLD_WARNING [KEY_THRESHOLD_WARNING ...]] Warning threshold for these values (key1[>alias],WarnRange key2[>alias],WarnRange). @@ -243,7 +245,10 @@ ``` -More info about options in Usage. +## Icinga2 configuration + +The Icinga2 command definition can be found here: (contrib/icinga2_check_command_definition.conf) + ## License diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/check_http_json.py new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/check_http_json.py --- old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/check_http_json.py 2020-03-31 18:15:06.000000000 +0200 +++ new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/check_http_json.py 2020-07-03 09:58:55.000000000 +0200 @@ -225,9 +225,9 @@ if self.rules.value_separator: value_separator = self.rules.value_separator self.helper = JsonHelper(self.data, separator, value_separator) - debugPrint(rules_args.debug, "rules:%s" % rules_args) - debugPrint(rules_args.debug, "separator:%s" % separator) - debugPrint(rules_args.debug, "value_separator:%s" % value_separator) + debugPrint(rules_args.debug, "rules: %s" % rules_args) + debugPrint(rules_args.debug, "separator: %s" % separator) + debugPrint(rules_args.debug, "value_separator: %s" % value_separator) self.metric_list = self.expandKeys(self.rules.metric_list) self.key_threshold_warning = self.expandKeys( self.rules.key_threshold_warning) @@ -346,6 +346,8 @@ def checkCritical(self): failure = '' + if not self.data: + failure = " Empty JSON data." if self.key_threshold_critical is not None: failure += self.checkThresholds(self.key_threshold_critical) if self.key_value_list_critical is not None: @@ -424,7 +426,7 @@ parser.add_argument('-s', '--ssl', action='store_true', help='use TLS to connect to remote host') parser.add_argument('-H', '--host', dest='host', - required=not ('-V' in sys.argv or '--version' in sys.argv), + required=not ('-V' in args or '--version' in args), help='remote host to query') parser.add_argument('-k', '--insecure', action='store_true', help='do not check server SSL certificate') @@ -524,10 +526,12 @@ print(message) -# Program entry point -if __name__ == "__main__": +def main(cliargs): + """ + Main entrypoint for CLI + """ - args = parseArgs(sys.argv[1:]) + args = parseArgs(cliargs) nagios = NagiosHelper() context = None @@ -607,7 +611,11 @@ json_data = response.read() except HTTPError as e: - nagios.append_unknown(" HTTPError[%s], url:%s" % (str(e.code), url)) + # Try to recover from HTTP Error, if there is JSON in the response + if "json" in e.info().get_content_subtype(): + json_data = e.read() + else: + nagios.append_unknown(" HTTPError[%s], url:%s" % (str(e.code), url)) except URLError as e: nagios.append_critical(" URLError[%s], url:%s" % (str(e.reason), url)) @@ -630,4 +638,9 @@ print(nagios.getMessage()) sys.exit(nagios.getCode()) + +if __name__ == "__main__": + # Program entry point + main(sys.argv[1:]) + #EOF diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/contrib/icinga2_check_command_definition.conf new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/contrib/icinga2_check_command_definition.conf --- old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/contrib/icinga2_check_command_definition.conf 1970-01-01 01:00:00.000000000 +0100 +++ new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/contrib/icinga2_check_command_definition.conf 2020-07-03 09:58:55.000000000 +0200 @@ -0,0 +1,106 @@ +object CheckCommand "http_json" { + import "plugin-check-command" + + command = [ PluginDir + "/check_http_json.py" ] + + arguments = { + "--host" = { + value = "$address$" + description = "Hostname or address of the interface to query" + required = true + } + "--port" = { + value = "$http_json_port$" + description = "TCP port number" + } + "--path" = { + value = "$http_json_path$" + description = "URL path to query (i.e.: /v1/service/xyz)" + } + "--timeout" = { + value = "$http_json_timeout$" + description = "Connection timeout (seconds)" + } + "--basic-auth" = { + value = "$http_json_basic_auth$" + description = "Basic auth string 'username:password'" + } + "--ssl" = { + set_if = "$http_json_ssl$" + description = "use TLS to connect to remote host" + } + "--insecure" = { + set_if = "$http_json_insecure$" + description = "do not check server SSL certificate" + } + "--cacert" = { + value = "$http_json_cacert_file$" + description = "path of cacert file to validate server cert" + } + "--cert" = { + value = "$http_json_cert_file$" + description = "client certificate in PEM format" + } + "--key" = { + value = "$http_json_key_file$" + description = "client certificate key file in PEM format ( if not bundled into the cert )" + } + "--data" = { + value = "$http_json_post_data$" + description = "the http payload to send as a POST" + } + "--headers" = { + value = "$http_json_headers$" + description = "additional http headers in JSON format to send with the request" + } + "--field_separator" = { + value = "$http_json_field_separator$" + description = "JSON Field separator, defaults to '.'; Select element in an array with '(' ')'" + } + "--value_separator" = { + value = "$http_json_value_separator$" + description = "JSON Value separator, defaults to ':'" + } + "--warning" = { + value = "$http_json_warning$" + description = "Warning threshold for these values, WarningRange is in the format [@]start:end" + } + "--critical" = { + value = "$http_json_critical$" + description = "Critical threshold for these values, CriticalRange is in the format [@]start:end" + } + "--key_exists" = { + value = "$http_json_key_exists$" + description = "Checks existence of these keys to determine status. Return warning if key is not present." + } + "--key_exists_critical" = { + value = "$http_json_key_exists_critical$" + description = "Checks existence of these keys to determine status. Return critical if key is not present." + } + "--key_equals" = { + value = "$http_json_key_equals$" + description = "Checks equality of these keys and values. Return warning if equality check fails" + } + "--key_equals_critical" = { + value = "$http_json_key_equals_critical$" + description = "Checks equality of these keys and values. Return critical if equality check fails" + } + "--key_equals_unknown" = { + value = "$http_json_key_equals_unknown$" + description = "Checks equality of these keys and values. Return unknown if equality check fails" + } + "--key_not_equals" = { + value = "$http_json_key_not_equals$" + description = "Checks equality of these keys and values (key[>alias],value key2,value2) to determine status. Multiple key values can be delimited with colon (key,value1:value2). Return warning if equality check succeeds." + } + "--key_not_equals_critical" = { + value = "$http_json_key_not_equals_critical$" + description = "Checks equality of these keys and values (key[>alias],value key2,value2) to determine status. Multiple key values can be delimited with colon (key,value1:value2). Return critical if equality check succeeds." + } + "--key_metrics" = { + value = "$http_json_key_metrics$" + description = "Gathers the values of these keys" + } + } +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/makefile new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/makefile --- old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/makefile 1970-01-01 01:00:00.000000000 +0100 +++ new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/makefile 2020-07-03 09:58:55.000000000 +0200 @@ -0,0 +1,9 @@ +.PHONY: lint test coverage + +lint: + python3 -m pylint check_http_json.py +test: + python3 -m unittest discover +coverage: + python3 -m coverage run -m unittest discover + python3 -m coverage report -m --include check_http_json.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/test/requirements.txt new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/test/requirements.txt --- old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/test/requirements.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/test/requirements.txt 2020-07-03 09:58:55.000000000 +0200 @@ -0,0 +1,2 @@ +coverage==5.0.3 +pylint==2.4.4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/test/test_check_http_json.py new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/test/test_check_http_json.py --- old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/test/test_check_http_json.py 2020-03-31 18:15:06.000000000 +0200 +++ new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/test/test_check_http_json.py 2020-07-03 09:58:55.000000000 +0200 @@ -256,7 +256,7 @@ # This should not throw a KeyError data = '{}' - self.check_data(rules.dash_q(['(0).Node,foobar', '(1).Node,missing']), data, WARNING_CODE) + self.check_data(rules.dash_q(['(0).Node,foobar', '(1).Node,missing']), data, CRITICAL_CODE) def test_subelem(self): @@ -274,3 +274,23 @@ self.check_data(rules.dash_E(['(*).capacity.value.too_deep']), data, CRITICAL_CODE) # Should not throw keyerror self.check_data(rules.dash_E(['foo']), data, CRITICAL_CODE) + + + def test_empty_key_value_array(self): + """ + https://github.com/drewkerrigan/nagios-http-json/issues/61 + """ + + rules = RulesHelper() + + # This should simply work + data = '[{"update_status": "finished"},{"update_status": "finished"}]' + self.check_data(rules.dash_q(['(*).update_status,finished']), data, OK_CODE) + + # This should warn us + data = '[{"update_status": "finished"},{"update_status": "failure"}]' + self.check_data(rules.dash_q(['(*).update_status,finished']), data, WARNING_CODE) + + # This should throw an error + data = '[]' + self.check_data(rules.dash_q(['(*).update_status,warn_me']), data, CRITICAL_CODE) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/test/test_cli.py new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/test/test_cli.py --- old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/test/test_cli.py 1970-01-01 01:00:00.000000000 +0100 +++ new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/test/test_cli.py 2020-07-03 09:58:55.000000000 +0200 @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 + + +import unittest +import unittest.mock as mock +import sys +import os + +sys.path.append('..') + +from check_http_json import debugPrint + + +class CLITest(unittest.TestCase): + """ + Tests for CLI + """ + + def setUp(self): + """ + Defining the exitcodes + """ + + self.exit_0 = 0 << 8 + self.exit_1 = 1 << 8 + self.exit_2 = 2 << 8 + self.exit_3 = 3 << 8 + + def test_debugprint(self): + with mock.patch('builtins.print') as mock_print: + debugPrint(True, 'debug') + mock_print.assert_called_once_with('debug') + + def test_debugprint_pprint(self): + with mock.patch('check_http_json.pprint') as mock_pprint: + debugPrint(True, 'debug', True) + mock_pprint.assert_called_once_with('debug') + + def test_cli_without_params(self): + + command = '/usr/bin/env python3 check_http_json.py > /dev/null 2>&1' + status = os.system(command) + + self.assertEqual(status, self.exit_2) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/test/test_main.py new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/test/test_main.py --- old/monitoring-plugins-http_json-2.0+git.1585671306.219e993/test/test_main.py 2020-03-31 18:15:06.000000000 +0200 +++ new/monitoring-plugins-http_json-2.1+git.1593763135.c23ebac/test/test_main.py 2020-07-03 09:58:55.000000000 +0200 @@ -8,37 +8,90 @@ sys.path.append('..') -from check_http_json import debugPrint +from check_http_json import main + + +class MockResponse(): + def __init__(self, status_code=200, content='{"foo": "bar"}'): + self.status_code = status_code + self.content = content + + def read(self): + return self.content class MainTest(unittest.TestCase): """ - Tests for main + Tests for Main """ - def setUp(self): - """ - Defining the exitcodes - """ - - self.exit_0 = 0 << 8 - self.exit_1 = 1 << 8 - self.exit_2 = 2 << 8 - self.exit_3 = 3 << 8 - - def test_debugprint(self): - with mock.patch('builtins.print') as mock_print: - debugPrint(True, 'debug') - mock_print.assert_called_once_with('debug') - - def test_debugprint_pprint(self): - with mock.patch('check_http_json.pprint') as mock_pprint: - debugPrint(True, 'debug', True) - mock_pprint.assert_called_once_with('debug') + @mock.patch('builtins.print') + def test_main_version(self, mock_print): + args = ['--version'] + + with self.assertRaises(SystemExit) as test: + main(args) + + mock_print.assert_called_once() + self.assertEqual(test.exception.code, 0) + + @mock.patch('builtins.print') + @mock.patch('urllib.request.urlopen') + def test_main_with_ssl(self, mock_request, mock_print): + args = '-H localhost --ssl'.split(' ') + + mock_request.return_value = MockResponse() + + with self.assertRaises(SystemExit) as test: + main(args) + + self.assertEqual(test.exception.code, 0) + + + @mock.patch('builtins.print') + @mock.patch('urllib.request.urlopen') + def test_main_with_parse_error(self, mock_request, mock_print): + args = '-H localhost'.split(' ') + + mock_request.return_value = MockResponse(content='not JSON') + + with self.assertRaises(SystemExit) as test: + main(args) + + self.assertTrue('Parser error' in str(mock_print.call_args)) + self.assertEqual(test.exception.code, 3) + + @mock.patch('builtins.print') + def test_main_with_url_error(self, mock_print): + args = '-H localhost'.split(' ') + + with self.assertRaises(SystemExit) as test: + main(args) + + self.assertTrue('URLError' in str(mock_print.call_args)) + self.assertEqual(test.exception.code, 3) + + @mock.patch('builtins.print') + @mock.patch('urllib.request.urlopen') + def test_main_with_http_error_no_json(self, mock_request, mock_print): + args = '-H localhost'.split(' ') + + mock_request.return_value = MockResponse(content='not JSON', status_code=503) + + with self.assertRaises(SystemExit) as test: + main(args) + + self.assertTrue('Parser error' in str(mock_print.call_args)) + self.assertEqual(test.exception.code, 3) + + @mock.patch('builtins.print') + @mock.patch('urllib.request.urlopen') + def test_main_with_http_error_valid_json(self, mock_request, mock_print): + args = '-H localhost'.split(' ') - def test_cli_without_params(self): + mock_request.return_value = MockResponse(status_code=503) - command = '/usr/bin/env python3 check_http_json.py > /dev/null 2>&1' - status = os.system(command) + with self.assertRaises(SystemExit) as test: + main(args) - self.assertEqual(status, self.exit_2) + self.assertEqual(test.exception.code, 0)