From 06fab10fe2bc33f40f54be568fe33722260de1e2 Mon Sep 17 00:00:00 2001 From: Drew Kerrigan Date: Mon, 18 Jul 2016 17:22:41 -0400 Subject: [PATCH 01/22] added (*) syntax --- check_http_json.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/check_http_json.py b/check_http_json.py index cfcc617..a1892cb 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -127,6 +127,28 @@ class JsonHelper: else: return (None, 'not_found') + def expandKey(self, key, keys): + if '(*)' not in key: + keys.append(key) + return keys + subElemKey = '' + if key.find('(*)') > 0: + subElemKey = key[:key.find('(*)')-1] + remainingKey = key[key.find('(*)')+3:] + elemData = self.get(subElemKey) + if elemData is (None, 'not_found'): + keys.append(key) + return keys + if subElemKey is not '': + subElemKey = subElemKey + '.' + for i in range(len(elemData)): + newKey = subElemKey + '(' + str(i) + ')' + remainingKey + newKeys = self.expandKey(newKey, []) + for j in newKeys: + keys.append(j) + + return keys + def _getKeyAlias(original_key): key = original_key alias = original_key @@ -230,7 +252,14 @@ class JsonRuleProcessor: warning = '' critical = '' if self.rules.metric_list != None: + metric_list = [] + for metric in self.rules.metric_list: + newKeys = self.helper.expandKey(metric, []) + for k in newKeys: + metric_list.append(k) + + for metric in metric_list: key = metric minimum = maximum = warn_range = crit_range = None uom = '' From 9be6a709a2a3e9d080e37b21fb02ebf0d06a50b2 Mon Sep 17 00:00:00 2001 From: Drew Kerrigan Date: Tue, 19 Jul 2016 11:02:28 -0400 Subject: [PATCH 02/22] syntax cleanup --- check_http_json.py | 427 ++++++++++++++++++++++++++++++--------------- 1 file changed, 290 insertions(+), 137 deletions(-) diff --git a/check_http_json.py b/check_http_json.py index a1892cb..2c0d2bf 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -3,11 +3,13 @@ """ Check HTTP JSON Nagios Plugin -Generic Nagios plugin which checks json values from a given endpoint against argument specified rules -and determines the status and performance data for that service. +Generic Nagios plugin which checks json values from a given endpoint against +argument specified rules and determines the status and performance data for +that service. """ -import httplib, urllib, urllib2, base64 +import urllib2 +import base64 import json import argparse import sys @@ -15,25 +17,28 @@ from pprint import pprint from urllib2 import HTTPError from urllib2 import URLError -# TEST = False - - OK_CODE = 0 WARNING_CODE = 1 CRITICAL_CODE = 2 UNKNOWN_CODE = 3 + class NagiosHelper: """Help with Nagios specific status string formatting.""" - message_prefixes = {OK_CODE: 'OK', WARNING_CODE: 'WARNING', CRITICAL_CODE: 'CRITICAL', UNKNOWN_CODE: 'UNKNOWN'} + message_prefixes = {OK_CODE: 'OK', + WARNING_CODE: 'WARNING', + CRITICAL_CODE: 'CRITICAL', + UNKNOWN_CODE: 'UNKNOWN'} performance_data = '' warning_message = '' critical_message = '' unknown_message = '' def getMessage(self): - """Build a status-prefixed message with optional performance data generated externally""" - text = "%s: Status %s." % (self.message_prefixes[self.getCode()], self.message_prefixes[self.getCode()]) + """Build a status-prefixed message with optional performance data + generated externally""" + text = "%s: Status %s." % (self.message_prefixes[self.getCode()], + self.message_prefixes[self.getCode()]) text += self.warning_message text += self.critical_message text += self.unknown_message @@ -53,17 +58,23 @@ class NagiosHelper: def append_warning(self, warning_message): self.warning_message += warning_message + def append_critical(self, critical_message): self.critical_message += critical_message + def append_unknown(self, unknown_message): self.critical_message += unknown_message - def append_metrics(self, (performance_data, warning_message, critical_message)): + + def append_metrics(self, (performance_data, + warning_message, critical_message)): self.performance_data += performance_data self.append_warning(warning_message) self.append_critical(critical_message) + class JsonHelper: - """Perform simple comparison operations against values in a given JSON dict""" + """Perform simple comparison operations against values in a given + JSON dict""" def __init__(self, json_data, separator): self.data = json_data self.separator = separator @@ -81,7 +92,8 @@ class JsonHelper: def getSubArrayElement(self, key, data): subElemKey = key[:key.find(self.arrayOpener)] - index = int(key[key.find(self.arrayOpener) + 1:key.find(self.arrayCloser)]) + index = int(key[key.find(self.arrayOpener) + + 1:key.find(self.arrayCloser)]) remainingKey = key[key.find(self.arrayCloser + self.separator) + 2:] if key.find(self.arrayCloser + self.separator) == -1: remainingKey = key[key.find(self.arrayCloser) + 1:] @@ -96,30 +108,45 @@ class JsonHelper: else: return (None, 'not_found') - def equals(self, key, value): return self.exists(key) and str(self.get(key)) in value.split(':') - def lte(self, key, value): return self.exists(key) and float(self.get(key)) <= float(value) - def lt(self, key, value): return self.exists(key) and float(self.get(key)) < float(value) - def gte(self, key, value): return self.exists(key) and float(self.get(key)) >= float(value) - def gt(self, key, value): return self.exists(key) and float(self.get(key)) > float(value) - def exists(self, key): return (self.get(key) != (None, 'not_found')) + def equals(self, key, value): + return self.exists(key) and \ + str(self.get(key)) in value.split(':') + + def lte(self, key, value): + return self.exists(key) and float(self.get(key)) <= float(value) + + def lt(self, key, value): + return self.exists(key) and float(self.get(key)) < float(value) + + def gte(self, key, value): + return self.exists(key) and float(self.get(key)) >= float(value) + + def gt(self, key, value): + return self.exists(key) and float(self.get(key)) > float(value) + + def exists(self, key): + return (self.get(key) != (None, 'not_found')) + def get(self, key, temp_data=''): - """Can navigate nested json keys with a dot format (Element.Key.NestedKey). Returns (None, 'not_found') if not found""" + """Can navigate nested json keys with a dot format + (Element.Key.NestedKey). Returns (None, 'not_found') if not found""" if temp_data: data = temp_data else: data = self.data if len(key) <= 0: return data - if key.find(self.separator) != -1 and key.find(self.arrayOpener) != -1 : - if key.find(self.separator) < key.find(self.arrayOpener) : + if key.find(self.separator) != -1 and \ + key.find(self.arrayOpener) != -1: + if key.find(self.separator) < key.find(self.arrayOpener): return self.getSubElement(key, data) else: return self.getSubArrayElement(key, data) else: - if key.find(self.separator) != -1 : + if key.find(self.separator) != -1: return self.getSubElement(key, data) else: - if key.find(self.arrayOpener) != -1 : + if key.find(self.arrayOpener) != -1: return self.getSubArrayElement(key, data) else: if key in data: @@ -149,6 +176,7 @@ class JsonHelper: return keys + def _getKeyAlias(original_key): key = original_key alias = original_key @@ -158,13 +186,16 @@ def _getKeyAlias(original_key): key, alias = keys return key, alias + class JsonRuleProcessor: - """Perform checks and gather values from a JSON dict given rules and metrics definitions""" + """Perform checks and gather values from a JSON dict given rules + and metrics definitions""" def __init__(self, json_data, rules_args): self.data = json_data self.rules = rules_args separator = '.' - if self.rules.separator: separator = self.rules.separator + if self.rules.separator: + separator = self.rules.separator self.helper = JsonHelper(self.data, separator) debugPrint(rules_args.debug, "rules:%s" % rules_args) debugPrint(rules_args.debug, "separator:%s" % separator) @@ -173,7 +204,7 @@ class JsonRuleProcessor: failure = '' for k in exists_list: key, alias = _getKeyAlias(k) - if (self.helper.exists(key) == False): + if (self.helper.exists(key) is False): failure += " Key %s did not exist." % alias return failure @@ -182,7 +213,7 @@ class JsonRuleProcessor: for kv in equality_list: k, v = kv.split(',') key, alias = _getKeyAlias(k) - if (self.helper.equals(key, v) == False): + if (self.helper.equals(key, v) is False): failure += " Value for key %s did not match %s." % (alias, v) return failure @@ -203,19 +234,27 @@ class JsonRuleProcessor: end = vals[1] if(start == '~'): if (invert and self.helper.lte(key, end)): - failure += " Value for key %s was less than or equal to %s." % (alias, end) + failure += " Value for key %s was less than or equal to %s." % \ + (alias, end) elif (not invert and self.helper.gt(key, end)): - failure += " Value for key %s was greater than %s." % (alias, end) + failure += " Value for key %s was greater than %s." % \ + (alias, end) elif(end == 'infinity'): if (invert and self.helper.gte(key, start)): - failure += " Value for key %s was greater than or equal to %s." % (alias, start) + failure += " Value for key %s was greater than or equal to %s." % \ + (alias, start) elif (not invert and self.helper.lt(key, start)): - failure += " Value for key %s was less than %s." % (alias, start) + failure += " Value for key %s was less than %s." % \ + (alias, start) else: - if (invert and self.helper.gte(key, start) and self.helper.lte(key, end)): - failure += " Value for key %s was inside the range %s:%s." % (alias, start, end) - elif (not invert and (self.helper.lt(key, start) or self.helper.gt(key, end))): - failure += " Value for key %s was outside the range %s:%s." % (alias, start, end) + if (invert and self.helper.gte(key, start) and + self.helper.lte(key, end)): + failure += " Value for key %s was inside the range %s:%s." % \ + (alias, start, end) + elif (not invert and (self.helper.lt(key, start) or + self.helper.gt(key, end))): + failure += " Value for key %s was outside the range %s:%s." % \ + (alias, start, end) return failure def checkThresholds(self, threshold_list): @@ -228,30 +267,31 @@ class JsonRuleProcessor: def checkWarning(self): failure = '' - if self.rules.key_threshold_warning != None: + if self.rules.key_threshold_warning is not None: failure += self.checkThresholds(self.rules.key_threshold_warning) - if self.rules.key_value_list != None: + if self.rules.key_value_list is not None: failure += self.checkEquality(self.rules.key_value_list) - if self.rules.key_list != None: + if self.rules.key_list is not None: failure += self.checkExists(self.rules.key_list) return failure def checkCritical(self): failure = '' - if self.rules.key_threshold_critical != None: + if self.rules.key_threshold_critical is not None: failure += self.checkThresholds(self.rules.key_threshold_critical) - if self.rules.key_value_list_critical != None: + if self.rules.key_value_list_critical is not None: failure += self.checkEquality(self.rules.key_value_list_critical) - if self.rules.key_list_critical != None: + if self.rules.key_list_critical is not None: failure += self.checkExists(self.rules.key_list_critical) return failure def checkMetrics(self): - """Return a Nagios specific performance metrics string given keys and parameter definitions""" + """Return a Nagios specific performance metrics string given keys + and parameter definitions""" metrics = '' warning = '' critical = '' - if self.rules.metric_list != None: + if self.rules.metric_list is not None: metric_list = [] for metric in self.rules.metric_list: @@ -266,67 +306,104 @@ class JsonRuleProcessor: if ',' in metric: vals = metric.split(',') if len(vals) == 2: - key,uom = vals + key, uom = vals if len(vals) == 4: - key,uom,warn_range,crit_range = vals + key, uom, warn_range, crit_range = vals if len(vals) == 6: - key,uom,warn_range,crit_range,minimum,maximum = vals + key, uom, warn_range, crit_range, + minimum, maximum = vals key, alias = _getKeyAlias(key) if self.helper.exists(key): metrics += "'%s'=%s" % (alias, self.helper.get(key)) - if uom: metrics += uom - if warn_range != None: + if uom: + metrics += uom + if warn_range is not None: warning += self.checkThreshold(key, alias, warn_range) metrics += ";%s" % warn_range - if crit_range != None: + if crit_range is not None: critical += self.checkThreshold(key, alias, crit_range) metrics += ";%s" % crit_range - if minimum != None: - critical += self.checkThreshold(key, alias, minimum + ':') + if minimum is not None: + critical += self.checkThreshold(key, alias, minimum + + ':') metrics += ";%s" % minimum - if maximum != None: - critical += self.checkThreshold(key, alias, '~:' + maximum) + if maximum is not None: + critical += self.checkThreshold(key, alias, '~:' + + maximum) metrics += ";%s" % maximum metrics += ' ' return ("%s" % metrics, warning, critical) -def parseArgs(): - parser = argparse.ArgumentParser(description= - 'Nagios plugin which checks json values from a given endpoint against argument specified rules\ - and determines the status and performance data for that service') - # parser.add_argument('-v', '--verbose', action='store_true', help='Verbose Output') - parser.add_argument('-d', '--debug', action='store_true', help='Debug mode.') +def parseArgs(): + parser = argparse.ArgumentParser(description='''Nagios plugin which + checks json values from a given endpoint against argument specified rules + and determines the status and performance data for that service''') + + parser.add_argument('-d', '--debug', action='store_true', + help='Debug mode.') parser.add_argument('-s', '--ssl', action='store_true', help='HTTPS mode.') - parser.add_argument('-H', '--host', dest='host', required=True, help='Host.') + parser.add_argument('-H', '--host', dest='host', required=True, + help='Host.') parser.add_argument('-P', '--port', dest='port', help='TCP port') parser.add_argument('-p', '--path', dest='path', help='Path.') - parser.add_argument('-t', '--timeout', type=int, help='Connection timeout (seconds)') - parser.add_argument('-B', '--basic-auth', dest='auth', help='Basic auth string "username:password"') - parser.add_argument('-D', '--data', dest='data', help='The http payload to send as a POST') - parser.add_argument('-A', '--headers', dest='headers', help='The http headers in JSON format.') + parser.add_argument('-t', '--timeout', type=int, + help='Connection timeout (seconds)') + parser.add_argument('-B', '--basic-auth', dest='auth', + help='Basic auth string "username:password"') + parser.add_argument('-D', '--data', dest='data', + help='The http payload to send as a POST') + parser.add_argument('-A', '--headers', dest='headers', + help='The http headers in JSON format.') parser.add_argument('-f', '--field_separator', dest='separator', - help='Json Field separator, defaults to "." ; Select element in an array with "(" ")"') - parser.add_argument('-w', '--warning', dest='key_threshold_warning', nargs='*', - help='Warning threshold for these values (key1[>alias],WarnRange key2[>alias],WarnRange). WarnRange is in the format [@]start:end, more information at nagios-plugins.org/doc/guidelines.html.') - parser.add_argument('-c', '--critical', dest='key_threshold_critical', nargs='*', - help='Critical threshold for these values (key1[>alias],CriticalRange key2[>alias],CriticalRange. CriticalRange is in the format [@]start:end, more information at nagios-plugins.org/doc/guidelines.html.') + help='''JSON Field separator, defaults to "." ; + Select element in an array with "(" ")"''') + parser.add_argument('-w', '--warning', dest='key_threshold_warning', + nargs='*', + help='''Warning threshold for these values + (key1[>alias],WarnRange key2[>alias],WarnRange). + WarnRange is in the format [@]start:end, more + information at + nagios-plugins.org/doc/guidelines.html.''') + parser.add_argument('-c', '--critical', dest='key_threshold_critical', + nargs='*', + help='''Critical threshold for these values + (key1[>alias],CriticalRange key2[>alias],CriticalRange. + CriticalRange is in the format [@]start:end, more + information at + nagios-plugins.org/doc/guidelines.html.''') parser.add_argument('-e', '--key_exists', dest='key_list', nargs='*', - help='Checks existence of these keys to determine status. Return warning if key is not present.') - parser.add_argument('-E', '--key_exists_critical', dest='key_list_critical', nargs='*', - help='Same as -e but return critical if key is not present.') + help='''Checks existence of these keys to determine + status. Return warning if key is not present.''') + parser.add_argument('-E', '--key_exists_critical', + dest='key_list_critical', + nargs='*', + help='''Same as -e but return critical if key is + not present.''') parser.add_argument('-q', '--key_equals', dest='key_value_list', nargs='*', - help='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 fails') - parser.add_argument('-Q', '--key_equals_critical', dest='key_value_list_critical', nargs='*', - help='Same as -q but return critical if equality check fails.') + help='''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 fails''') + parser.add_argument('-Q', '--key_equals_critical', + dest='key_value_list_critical', nargs='*', + help='''Same as -q but return critical if + equality check fails.''') parser.add_argument('-m', '--key_metric', dest='metric_list', nargs='*', - help='Gathers the values of these keys (key[>alias],UnitOfMeasure,WarnRange,CriticalRange,Min,Max) for Nagios performance data.\ - More information about Range format and units of measure for nagios can be found at nagios-plugins.org/doc/guidelines.html\ - Additional formats for this parameter are: (key[>alias]), (key[>alias],UnitOfMeasure), (key[>alias],UnitOfMeasure,WarnRange,CriticalRange).') + help='''Gathers the values of these keys (key[>alias], + UnitOfMeasure,WarnRange,CriticalRange,Min,Max) for + Nagios performance data. More information about Range + format and units of measure for nagios can be found at + nagios-plugins.org/doc/guidelines.html + Additional formats for this parameter are: + (key[>alias]), (key[>alias],UnitOfMeasure), + (key[>alias],UnitOfMeasure,WarnRange, + CriticalRange).''') return parser.parse_args() + def debugPrint(debug_flag, message, pretty_flag=False): if debug_flag: if pretty_flag: @@ -336,26 +413,49 @@ def debugPrint(debug_flag, message, pretty_flag=False): if __name__ == "__main__" and len(sys.argv) >= 2 and sys.argv[1] == 'UnitTest': import unittest + class RulesHelper: separator = '.' debug = False - key_threshold_warning,key_value_list,key_list,key_threshold_critical,key_value_list_critical,key_list_critical,metric_list = None, None, None, None, None, None, None + key_threshold_warning = None + key_value_list = None + key_list = None + key_threshold_critical = None + key_value_list_critical = None + key_list_critical = None + metric_list = None + def dash_m(self, data): - self.metric_list = data; return self + self.metric_list = data + return self + def dash_e(self, data): - self.key_list = data; return self + self.key_list = data + return self + def dash_E(self, data): - self.key_list_critical = data; return self + self.key_list_critical = data + return self + def dash_q(self, data): - self.key_value_list = data; return self + self.key_value_list = data + return self + def dash_Q(self, data): - self.key_value_list_critical = data; return self + self.key_value_list_critical = data + return self + def dash_w(self, data): - self.key_threshold_warning = data; return self + self.key_threshold_warning = data + return self + def dash_c(self, data): - self.key_threshold_critical = data; return self + self.key_threshold_critical = data + return self + class UnitTest(unittest.TestCase): rules = RulesHelper() + def check_data(self, args, jsondata, code): data = json.loads(jsondata) nagios = NagiosHelper() @@ -364,60 +464,111 @@ if __name__ == "__main__" and len(sys.argv) >= 2 and sys.argv[1] == 'UnitTest': nagios.append_critical(processor.checkCritical()) nagios.append_metrics(processor.checkMetrics()) self.assertEqual(code, nagios.getCode()) + def test_metrics(self): - self.check_data(RulesHelper().dash_m(['metric,,1:4,1:5']), '{"metric": 5}', WARNING_CODE) - self.check_data(RulesHelper().dash_m(['metric,,1:5,1:4']), '{"metric": 5}', CRITICAL_CODE) - self.check_data(RulesHelper().dash_m(['metric,,1:5,1:5,6,10']), '{"metric": 5}', CRITICAL_CODE) - self.check_data(RulesHelper().dash_m(['metric,,1:5,1:5,1,4']), '{"metric": 5}', CRITICAL_CODE) - self.check_data(RulesHelper().dash_m(['metric,s,@1:4,@6:10,1,10']), '{"metric": 5}', OK_CODE) + self.check_data(RulesHelper().dash_m(['metric,,1:4,1:5']), + '{"metric": 5}', WARNING_CODE) + self.check_data(RulesHelper().dash_m(['metric,,1:5,1:4']), + '{"metric": 5}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_m(['metric,,1:5,1:5,6,10']), + '{"metric": 5}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_m(['metric,,1:5,1:5,1,4']), + '{"metric": 5}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_m(['metric,s,@1:4,@6:10,1,10']), + '{"metric": 5}', OK_CODE) + def test_exists(self): - self.check_data(RulesHelper().dash_e(['nothere']), '{"metric": 5}', WARNING_CODE) - self.check_data(RulesHelper().dash_E(['nothere']), '{"metric": 5}', CRITICAL_CODE) - self.check_data(RulesHelper().dash_e(['metric']), '{"metric": 5}', OK_CODE) + self.check_data(RulesHelper().dash_e(['nothere']), + '{"metric": 5}', WARNING_CODE) + self.check_data(RulesHelper().dash_E(['nothere']), + '{"metric": 5}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_e(['metric']), + '{"metric": 5}', OK_CODE) + def test_equality(self): - self.check_data(RulesHelper().dash_q(['metric,6']), '{"metric": 5}', WARNING_CODE) - self.check_data(RulesHelper().dash_Q(['metric,6']), '{"metric": 5}', CRITICAL_CODE) - self.check_data(RulesHelper().dash_q(['metric,5']), '{"metric": 5}', OK_CODE) + self.check_data(RulesHelper().dash_q(['metric,6']), + '{"metric": 5}', WARNING_CODE) + self.check_data(RulesHelper().dash_Q(['metric,6']), + '{"metric": 5}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_q(['metric,5']), + '{"metric": 5}', OK_CODE) + def test_warning_thresholds(self): - self.check_data(RulesHelper().dash_w(['metric,5']), '{"metric": 5}', OK_CODE) - self.check_data(RulesHelper().dash_w(['metric,5:']), '{"metric": 5}', OK_CODE) - self.check_data(RulesHelper().dash_w(['metric,~:5']), '{"metric": 5}', OK_CODE) - self.check_data(RulesHelper().dash_w(['metric,1:5']), '{"metric": 5}', OK_CODE) - self.check_data(RulesHelper().dash_w(['metric,@5']), '{"metric": 6}', OK_CODE) - self.check_data(RulesHelper().dash_w(['metric,@5:']), '{"metric": 4}', OK_CODE) - self.check_data(RulesHelper().dash_w(['metric,@~:5']), '{"metric": 6}', OK_CODE) - self.check_data(RulesHelper().dash_w(['metric,@1:5']), '{"metric": 6}', OK_CODE) - self.check_data(RulesHelper().dash_w(['metric,5']), '{"metric": 6}', WARNING_CODE) - self.check_data(RulesHelper().dash_w(['metric,5:']), '{"metric": 4}', WARNING_CODE) - self.check_data(RulesHelper().dash_w(['metric,~:5']), '{"metric": 6}', WARNING_CODE) - self.check_data(RulesHelper().dash_w(['metric,1:5']), '{"metric": 6}', WARNING_CODE) - self.check_data(RulesHelper().dash_w(['metric,@5']), '{"metric": 5}', WARNING_CODE) - self.check_data(RulesHelper().dash_w(['metric,@5:']), '{"metric": 5}', WARNING_CODE) - self.check_data(RulesHelper().dash_w(['metric,@~:5']), '{"metric": 5}', WARNING_CODE) - self.check_data(RulesHelper().dash_w(['metric,@1:5']), '{"metric": 5}', WARNING_CODE) + self.check_data(RulesHelper().dash_w(['metric,5']), + '{"metric": 5}', OK_CODE) + self.check_data(RulesHelper().dash_w(['metric,5:']), + '{"metric": 5}', OK_CODE) + self.check_data(RulesHelper().dash_w(['metric,~:5']), + '{"metric": 5}', OK_CODE) + self.check_data(RulesHelper().dash_w(['metric,1:5']), + '{"metric": 5}', OK_CODE) + self.check_data(RulesHelper().dash_w(['metric,@5']), + '{"metric": 6}', OK_CODE) + self.check_data(RulesHelper().dash_w(['metric,@5:']), + '{"metric": 4}', OK_CODE) + self.check_data(RulesHelper().dash_w(['metric,@~:5']), + '{"metric": 6}', OK_CODE) + self.check_data(RulesHelper().dash_w(['metric,@1:5']), + '{"metric": 6}', OK_CODE) + self.check_data(RulesHelper().dash_w(['metric,5']), + '{"metric": 6}', WARNING_CODE) + self.check_data(RulesHelper().dash_w(['metric,5:']), + '{"metric": 4}', WARNING_CODE) + self.check_data(RulesHelper().dash_w(['metric,~:5']), + '{"metric": 6}', WARNING_CODE) + self.check_data(RulesHelper().dash_w(['metric,1:5']), + '{"metric": 6}', WARNING_CODE) + self.check_data(RulesHelper().dash_w(['metric,@5']), + '{"metric": 5}', WARNING_CODE) + self.check_data(RulesHelper().dash_w(['metric,@5:']), + '{"metric": 5}', WARNING_CODE) + self.check_data(RulesHelper().dash_w(['metric,@~:5']), + '{"metric": 5}', WARNING_CODE) + self.check_data(RulesHelper().dash_w(['metric,@1:5']), + '{"metric": 5}', WARNING_CODE) + def test_critical_thresholds(self): - self.check_data(RulesHelper().dash_c(['metric,5']), '{"metric": 5}', OK_CODE) - self.check_data(RulesHelper().dash_c(['metric,5:']), '{"metric": 5}', OK_CODE) - self.check_data(RulesHelper().dash_c(['metric,~:5']), '{"metric": 5}', OK_CODE) - self.check_data(RulesHelper().dash_c(['metric,1:5']), '{"metric": 5}', OK_CODE) - self.check_data(RulesHelper().dash_c(['metric,@5']), '{"metric": 6}', OK_CODE) - self.check_data(RulesHelper().dash_c(['metric,@5:']), '{"metric": 4}', OK_CODE) - self.check_data(RulesHelper().dash_c(['metric,@~:5']), '{"metric": 6}', OK_CODE) - self.check_data(RulesHelper().dash_c(['metric,@1:5']), '{"metric": 6}', OK_CODE) - self.check_data(RulesHelper().dash_c(['metric,5']), '{"metric": 6}', CRITICAL_CODE) - self.check_data(RulesHelper().dash_c(['metric,5:']), '{"metric": 4}', CRITICAL_CODE) - self.check_data(RulesHelper().dash_c(['metric,~:5']), '{"metric": 6}', CRITICAL_CODE) - self.check_data(RulesHelper().dash_c(['metric,1:5']), '{"metric": 6}', CRITICAL_CODE) - self.check_data(RulesHelper().dash_c(['metric,@5']), '{"metric": 5}', CRITICAL_CODE) - self.check_data(RulesHelper().dash_c(['metric,@5:']), '{"metric": 5}', CRITICAL_CODE) - self.check_data(RulesHelper().dash_c(['metric,@~:5']), '{"metric": 5}', CRITICAL_CODE) - self.check_data(RulesHelper().dash_c(['metric,@1:5']), '{"metric": 5}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_c(['metric,5']), + '{"metric": 5}', OK_CODE) + self.check_data(RulesHelper().dash_c(['metric,5:']), + '{"metric": 5}', OK_CODE) + self.check_data(RulesHelper().dash_c(['metric,~:5']), + '{"metric": 5}', OK_CODE) + self.check_data(RulesHelper().dash_c(['metric,1:5']), + '{"metric": 5}', OK_CODE) + self.check_data(RulesHelper().dash_c(['metric,@5']), + '{"metric": 6}', OK_CODE) + self.check_data(RulesHelper().dash_c(['metric,@5:']), + '{"metric": 4}', OK_CODE) + self.check_data(RulesHelper().dash_c(['metric,@~:5']), + '{"metric": 6}', OK_CODE) + self.check_data(RulesHelper().dash_c(['metric,@1:5']), + '{"metric": 6}', OK_CODE) + self.check_data(RulesHelper().dash_c(['metric,5']), + '{"metric": 6}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_c(['metric,5:']), + '{"metric": 4}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_c(['metric,~:5']), + '{"metric": 6}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_c(['metric,1:5']), + '{"metric": 6}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_c(['metric,@5']), + '{"metric": 5}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_c(['metric,@5:']), + '{"metric": 5}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_c(['metric,@~:5']), + '{"metric": 5}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_c(['metric,@1:5']), + '{"metric": 5}', CRITICAL_CODE) + def test_separator(self): rules = RulesHelper() rules.separator = '_' self.check_data( - rules.dash_q(['(0)_gauges_jvm.buffers.direct.capacity(1)_value,1234']), - '[{ "gauges": { "jvm.buffers.direct.capacity": [{"value": 215415},{"value": 1234}]}}]', + rules.dash_q( + ['(0)_gauges_jvm.buffers.direct.capacity(1)_value,1234']), + '''[{ "gauges": { "jvm.buffers.direct.capacity": [ + {"value": 215415},{"value": 1234}]}}]''', OK_CODE) unittest.main() exit(0) @@ -430,22 +581,24 @@ if __name__ == "__main__": url = "https://%s" % args.host else: url = "http://%s" % args.host - if args.port: url += ":%s" % args.port - if args.path: url += "/%s" % args.path + if args.port: + url += ":%s" % args.port + if args.path: + url += "/%s" % args.path debugPrint(args.debug, "url:%s" % url) - # Attempt to reach the endpoint try: req = urllib2.Request(url) if args.auth: base64str = base64.encodestring(args.auth).replace('\n', '') req.add_header('Authorization', 'Basic %s' % base64str) if args.headers: - headers=json.loads(args.headers) + headers = json.loads(args.headers) debugPrint(args.debug, "Headers:\n %s" % headers) for header in headers: req.add_header(header, headers[header]) if args.timeout and args.data: - response = urllib2.urlopen(req, timeout=args.timeout, data=args.data) + response = urllib2.urlopen(req, timeout=args.timeout, + data=args.data) elif args.timeout: response = urllib2.urlopen(req, timeout=args.timeout) elif args.data: From 49502253934fc7b293d24a095dac7c4266f94a0d Mon Sep 17 00:00:00 2001 From: Drew Kerrigan Date: Tue, 19 Jul 2016 12:43:16 -0400 Subject: [PATCH 03/22] adding support for (*) to all flags --- check_http_json.py | 73 +++++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/check_http_json.py b/check_http_json.py index 2c0d2bf..809ddd3 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -199,6 +199,26 @@ class JsonRuleProcessor: self.helper = JsonHelper(self.data, separator) debugPrint(rules_args.debug, "rules:%s" % rules_args) debugPrint(rules_args.debug, "separator:%s" % separator) + self.metric_list = self.expandKeys(self.rules.metric_list) + self.key_threshold_warning = self.expandKeys( + self.rules.key_threshold_warning) + self.key_threshold_critical = self.expandKeys( + self.rules.key_threshold_critical) + self.key_value_list = self.expandKeys(self.rules.key_value_list) + self.key_list = self.expandKeys(self.rules.key_list) + self.key_value_list_critical = self.expandKeys( + self.rules.key_value_list_critical) + self.key_list_critical = self.expandKeys(self.rules.key_list_critical) + + def expandKeys(self, src): + if src is None: + return + dest = [] + for key in src: + newKeys = self.helper.expandKey(key, []) + for k in newKeys: + dest.append(k) + return dest def checkExists(self, exists_list): failure = '' @@ -267,22 +287,22 @@ class JsonRuleProcessor: def checkWarning(self): failure = '' - if self.rules.key_threshold_warning is not None: - failure += self.checkThresholds(self.rules.key_threshold_warning) - if self.rules.key_value_list is not None: - failure += self.checkEquality(self.rules.key_value_list) - if self.rules.key_list is not None: - failure += self.checkExists(self.rules.key_list) + if self.key_threshold_warning is not None: + failure += self.checkThresholds(self.key_threshold_warning) + if self.key_value_list is not None: + failure += self.checkEquality(self.key_value_list) + if self.key_list is not None: + failure += self.checkExists(self.key_list) return failure def checkCritical(self): failure = '' - if self.rules.key_threshold_critical is not None: - failure += self.checkThresholds(self.rules.key_threshold_critical) - if self.rules.key_value_list_critical is not None: - failure += self.checkEquality(self.rules.key_value_list_critical) - if self.rules.key_list_critical is not None: - failure += self.checkExists(self.rules.key_list_critical) + if self.key_threshold_critical is not None: + failure += self.checkThresholds(self.key_threshold_critical) + if self.key_value_list_critical is not None: + failure += self.checkEquality(self.key_value_list_critical) + if self.key_list_critical is not None: + failure += self.checkExists(self.key_list_critical) return failure def checkMetrics(self): @@ -291,15 +311,8 @@ class JsonRuleProcessor: metrics = '' warning = '' critical = '' - if self.rules.metric_list is not None: - metric_list = [] - - for metric in self.rules.metric_list: - newKeys = self.helper.expandKey(metric, []) - for k in newKeys: - metric_list.append(k) - - for metric in metric_list: + if self.metric_list is not None: + for metric in self.metric_list: key = metric minimum = maximum = warn_range = crit_range = None uom = '' @@ -310,8 +323,8 @@ class JsonRuleProcessor: if len(vals) == 4: key, uom, warn_range, crit_range = vals if len(vals) == 6: - key, uom, warn_range, crit_range, - minimum, maximum = vals + key, uom, warn_range, crit_range, \ + minimum, maximum = vals key, alias = _getKeyAlias(key) if self.helper.exists(key): metrics += "'%s'=%s" % (alias, self.helper.get(key)) @@ -476,6 +489,8 @@ if __name__ == "__main__" and len(sys.argv) >= 2 and sys.argv[1] == 'UnitTest': '{"metric": 5}', CRITICAL_CODE) self.check_data(RulesHelper().dash_m(['metric,s,@1:4,@6:10,1,10']), '{"metric": 5}', OK_CODE) + self.check_data(RulesHelper().dash_m(['(*).value,s,1:5,1:5']), + '[{"value": 5},{"value": 100}]', CRITICAL_CODE) def test_exists(self): self.check_data(RulesHelper().dash_e(['nothere']), @@ -526,6 +541,8 @@ if __name__ == "__main__" and len(sys.argv) >= 2 and sys.argv[1] == 'UnitTest': '{"metric": 5}', WARNING_CODE) self.check_data(RulesHelper().dash_w(['metric,@1:5']), '{"metric": 5}', WARNING_CODE) + self.check_data(RulesHelper().dash_w(['(*).value,@1:5']), + '[{"value": 5},{"value": 1000}]', WARNING_CODE) def test_critical_thresholds(self): self.check_data(RulesHelper().dash_c(['metric,5']), @@ -560,6 +577,8 @@ if __name__ == "__main__" and len(sys.argv) >= 2 and sys.argv[1] == 'UnitTest': '{"metric": 5}', CRITICAL_CODE) self.check_data(RulesHelper().dash_c(['metric,@1:5']), '{"metric": 5}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_c(['(*).value,@1:5']), + '[{"value": 5},{"value": 1000}]', CRITICAL_CODE) def test_separator(self): rules = RulesHelper() @@ -570,6 +589,14 @@ if __name__ == "__main__" and len(sys.argv) >= 2 and sys.argv[1] == 'UnitTest': '''[{ "gauges": { "jvm.buffers.direct.capacity": [ {"value": 215415},{"value": 1234}]}}]''', OK_CODE) + self.check_data( + rules.dash_q( + ['(*)_gauges_jvm.buffers.direct.capacity(1)_value,1234']), + '''[{ "gauges": { "jvm.buffers.direct.capacity": [ + {"value": 215415},{"value": 1234}]}}, + { "gauges": { "jvm.buffers.direct.capacity": [ + {"value": 215415},{"value": 1235}]}}]''', + WARNING_CODE) unittest.main() exit(0) From e4633696717705360f1c3ee48f7a4cb3f2eacdf4 Mon Sep 17 00:00:00 2001 From: Robert Nemeti Date: Thu, 10 Aug 2017 10:28:02 +0200 Subject: [PATCH 04/22] added insecure argument for the ssl connections --- check_http_json.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/check_http_json.py b/check_http_json.py index dac67ec..c723b9f 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -11,6 +11,7 @@ import httplib, urllib, urllib2, base64 import json import argparse import sys +import ssl from pprint import pprint from urllib2 import HTTPError from urllib2 import URLError @@ -269,6 +270,7 @@ def parseArgs(): # parser.add_argument('-v', '--verbose', action='store_true', help='Verbose Output') parser.add_argument('-d', '--debug', action='store_true', help='Debug mode.') parser.add_argument('-s', '--ssl', action='store_true', help='HTTPS mode.') + parser.add_argument('-k', '--insecure', action='store_true', help='do not check server SSL certificate') parser.add_argument('-H', '--host', dest='host', required=True, help='Host.') parser.add_argument('-P', '--port', dest='port', help='TCP port') parser.add_argument('-p', '--path', dest='path', help='Path.') @@ -404,6 +406,11 @@ if __name__ == "__main__": if args.port: url += ":%s" % args.port if args.path: url += "/%s" % args.path debugPrint(args.debug, "url:%s" % url) + if args.insecure: + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + else: + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + context.verify_mode = ssl.CERT_OPTIONAL # Attempt to reach the endpoint try: req = urllib2.Request(url) @@ -416,13 +423,13 @@ if __name__ == "__main__": for header in headers: req.add_header(header, headers[header]) if args.timeout and args.data: - response = urllib2.urlopen(req, timeout=args.timeout, data=args.data) + response = urllib2.urlopen(req, timeout=args.timeout, data=args.data, context=context) elif args.timeout: - response = urllib2.urlopen(req, timeout=args.timeout) + response = urllib2.urlopen(req, timeout=args.timeout, context=context) elif args.data: - response = urllib2.urlopen(req, data=args.data) + response = urllib2.urlopen(req, data=args.data, context=context) else: - response = urllib2.urlopen(req) + response = urllib2.urlopen(req, context=context) except HTTPError as e: nagios.append_unknown("HTTPError[%s], url:%s" % (str(e.code), url)) except URLError as e: From 965626543965ca3dada49d26204ca6777af656ec Mon Sep 17 00:00:00 2001 From: Robert Nemeti Date: Thu, 10 Aug 2017 10:29:45 +0200 Subject: [PATCH 05/22] print current value in the icinga message --- check_http_json.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/check_http_json.py b/check_http_json.py index c723b9f..8717a31 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -182,19 +182,19 @@ class JsonRuleProcessor: end = vals[1] if(start == '~'): if (invert and self.helper.lte(key, end)): - failure += " Value for key %s was less than or equal to %s." % (alias, end) + failure += " Value (%s) for key %s was less than or equal to %s." % (self.helper.get(key), alias, end) elif (not invert and self.helper.gt(key, end)): - failure += " Value for key %s was greater than %s." % (alias, end) + failure += " Value (%s) for key %s was greater than %s." % (self.helper.get(key), alias, end) elif(end == 'infinity'): if (invert and self.helper.gte(key, start)): - failure += " Value for key %s was greater than or equal to %s." % (alias, start) + failure += " Value (%s) for key %s was greater than or equal to %s." % (self.helper.get(key), alias, start) elif (not invert and self.helper.lt(key, start)): - failure += " Value for key %s was less than %s." % (alias, start) + failure += " Value (%s) for key %s was less than %s." % (self.helper.get(key), alias, start) else: if (invert and self.helper.gte(key, start) and self.helper.lte(key, end)): - failure += " Value for key %s was inside the range %s:%s." % (alias, start, end) + failure += " Value (%s) for key %s was inside the range %s:%s." % (self.helper.get(key), alias, start, end) elif (not invert and (self.helper.lt(key, start) or self.helper.gt(key, end))): - failure += " Value for key %s was outside the range %s:%s." % (alias, start, end) + failure += " Value (%s) for key %s was outside the range %s:%s." % (self.helper.get(key), alias, start, end) return failure def checkThresholds(self, threshold_list): From 1e707a4b6ad4d7a651f4a2e836f1e03878a756b4 Mon Sep 17 00:00:00 2001 From: Robert Nemeti Date: Thu, 10 Aug 2017 15:05:53 +0200 Subject: [PATCH 06/22] add repo and upstream info --- check_http_json.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/check_http_json.py b/check_http_json.py index 8717a31..81dde37 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -5,6 +5,9 @@ Check HTTP JSON Nagios Plugin Generic Nagios plugin which checks json values from a given endpoint against argument specified rules and determines the status and performance data for that service. +Git repo found at: ssh://git@app01.stash.office.infra.cgn.travian.info:7999/sys/icinga_check_http_json.git +Branch: tg +Upstream: https://github.com/drewkerrigan/nagios-http-json """ import httplib, urllib, urllib2, base64 From 89f42c15a01adab28cc0651dec7c0b15da36ab47 Mon Sep 17 00:00:00 2001 From: Robert Nemeti Date: Thu, 10 Aug 2017 15:41:35 +0200 Subject: [PATCH 07/22] use python2.7 because on centos 6 (icinga) the default python is 2.6 and doesn;t have the required ssl libraries --- check_http_json.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check_http_json.py b/check_http_json.py index 81dde37..1f5c0ba 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python2.7 """ Check HTTP JSON Nagios Plugin From d164a1250cdb13491d5084b2d31d7d32e2808567 Mon Sep 17 00:00:00 2001 From: Robert Nemeti Date: Wed, 10 Jan 2018 10:23:34 +0100 Subject: [PATCH 08/22] add key,value non equality check, the opposite of the -q and -Q --- check_http_json.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/check_http_json.py b/check_http_json.py index 1f5c0ba..5c72386 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -168,6 +168,15 @@ class JsonRuleProcessor: failure += " Value for key %s did not match %s." % (alias, v) return failure + def checkNonEquality(self, equality_list): + failure = '' + for kv in equality_list: + k, v = kv.split(',') + key, alias = _getKeyAlias(k) + if (self.helper.equals(key, v) == True): + failure += " Value for key %s matches %s." % (alias, v) + return failure + def checkThreshold(self, key, alias, r): failure = '' invert = False @@ -214,6 +223,8 @@ class JsonRuleProcessor: failure += self.checkThresholds(self.rules.key_threshold_warning) if self.rules.key_value_list != None: failure += self.checkEquality(self.rules.key_value_list) + if self.rules.key_value_list_not != None: + failure += self.checkNonEquality(self.rules.key_value_list_not) if self.rules.key_list != None: failure += self.checkExists(self.rules.key_list) return failure @@ -224,6 +235,8 @@ class JsonRuleProcessor: failure += self.checkThresholds(self.rules.key_threshold_critical) if self.rules.key_value_list_critical != None: failure += self.checkEquality(self.rules.key_value_list_critical) + if self.rules.key_value_list_not_critical != None: + failure += self.checkNonEquality(self.rules.key_value_list_not_critical) if self.rules.key_list_critical != None: failure += self.checkExists(self.rules.key_list_critical) return failure @@ -296,6 +309,11 @@ def parseArgs(): Multiple key values can be delimited with colon (key,value1:value2). Return warning if equality check fails') parser.add_argument('-Q', '--key_equals_critical', dest='key_value_list_critical', nargs='*', help='Same as -q but return critical if equality check fails.') + parser.add_argument('-y', '--key_not_equals', dest='key_value_list_not', nargs='*', + help='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') + parser.add_argument('-Y', '--key_not_equals_critical', dest='key_value_list_not_critical', nargs='*', + help='Same as -q but return critical if equality check succeeds.') parser.add_argument('-m', '--key_metric', dest='metric_list', nargs='*', help='Gathers the values of these keys (key[>alias],UnitOfMeasure,WarnRange,CriticalRange,Min,Max) for Nagios performance data.\ More information about Range format and units of measure for nagios can be found at nagios-plugins.org/doc/guidelines.html\ @@ -315,7 +333,7 @@ if __name__ == "__main__" and len(sys.argv) >= 2 and sys.argv[1] == 'UnitTest': class RulesHelper: separator = '.' debug = False - key_threshold_warning,key_value_list,key_list,key_threshold_critical,key_value_list_critical,key_list_critical,metric_list = None, None, None, None, None, None, None + key_threshold_warning,key_value_list,key_value_list_not,key_list,key_threshold_critical,key_value_list_critical,key_value_list_not_critical,key_list_critical,metric_list = None, None, None, None, None, None, None, None, None def dash_m(self, data): self.metric_list = data; return self def dash_e(self, data): @@ -326,6 +344,10 @@ if __name__ == "__main__" and len(sys.argv) >= 2 and sys.argv[1] == 'UnitTest': self.key_value_list = data; return self def dash_Q(self, data): self.key_value_list_critical = data; return self + def dash_y(self, data): + self.key_value_list_not = data; return self + def dash_Y(self, data): + self.key_value_list_not_critical = data; return self def dash_w(self, data): self.key_threshold_warning = data; return self def dash_c(self, data): @@ -354,6 +376,10 @@ if __name__ == "__main__" and len(sys.argv) >= 2 and sys.argv[1] == 'UnitTest': self.check_data(RulesHelper().dash_q(['metric,6']), '{"metric": 5}', WARNING_CODE) self.check_data(RulesHelper().dash_Q(['metric,6']), '{"metric": 5}', CRITICAL_CODE) self.check_data(RulesHelper().dash_q(['metric,5']), '{"metric": 5}', OK_CODE) + def test_non_equality(self): + self.check_data(RulesHelper().dash_y(['metric,6']), '{"metric": 6}', WARNING_CODE) + self.check_data(RulesHelper().dash_Y(['metric,6']), '{"metric": 6}', CRITICAL_CODE) + self.check_data(RulesHelper().dash_y(['metric,5']), '{"metric": 6}', OK_CODE) def test_warning_thresholds(self): self.check_data(RulesHelper().dash_w(['metric,5']), '{"metric": 5}', OK_CODE) self.check_data(RulesHelper().dash_w(['metric,5:']), '{"metric": 5}', OK_CODE) From 67136a4a2bf4ad3479e35034ca10e9dff7ccc1b8 Mon Sep 17 00:00:00 2001 From: Robert Nemeti Date: Thu, 15 Feb 2018 17:04:04 +0100 Subject: [PATCH 09/22] add client ssl cert support --- check_http_json.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/check_http_json.py b/check_http_json.py index 5c72386..ccc8b5f 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -287,6 +287,9 @@ def parseArgs(): parser.add_argument('-d', '--debug', action='store_true', help='Debug mode.') parser.add_argument('-s', '--ssl', action='store_true', help='HTTPS mode.') parser.add_argument('-k', '--insecure', action='store_true', help='do not check server SSL certificate') + parser.add_argument('--cacert', required=('-s' in sys.argv or '--ssl' in sys.argv) and not ('-k' in sys.argv or '--insecure' in sys.argv), dest='cacert', help='SSL CA certificate') + parser.add_argument('--cert', required=('-s' in sys.argv or '--ssl' in sys.argv) and not ('-k' in sys.argv or '--insecure' in sys.argv), dest='cert', help='SSL client certificate') + parser.add_argument('--key', dest='key', help='SSL client key ( if not bundled into the cert )') parser.add_argument('-H', '--host', dest='host', required=True, help='Host.') parser.add_argument('-P', '--port', dest='port', help='TCP port') parser.add_argument('-p', '--path', dest='path', help='Path.') @@ -430,16 +433,18 @@ if __name__ == "__main__": nagios = NagiosHelper() if args.ssl: url = "https://%s" % args.host + if args.insecure: + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + else: + context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + context.verify_mode = ssl.CERT_OPTIONAL + context.load_verify_locations(args.cacert) + context.load_cert_chain(args.cert,keyfile=args.key) else: url = "http://%s" % args.host if args.port: url += ":%s" % args.port if args.path: url += "/%s" % args.path debugPrint(args.debug, "url:%s" % url) - if args.insecure: - context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) - else: - context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) - context.verify_mode = ssl.CERT_OPTIONAL # Attempt to reach the endpoint try: req = urllib2.Request(url) From 9dd6323b85b9541bc353a7cecf4e1ada97225e26 Mon Sep 17 00:00:00 2001 From: Chase Lambert Date: Mon, 2 Apr 2018 09:34:00 -0400 Subject: [PATCH 10/22] Better failure message for exact keys --- check_http_json.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/check_http_json.py b/check_http_json.py index dac67ec..2d614e4 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -161,7 +161,7 @@ class JsonRuleProcessor: k, v = kv.split(',') key, alias = _getKeyAlias(k) if (self.helper.equals(key, v) == False): - failure += " Value for key %s did not match %s." % (alias, v) + failure += " Key %s mismatch. %s != %s" % (alias, v, self.helper.get(key)) return failure def checkThreshold(self, key, alias, r): From 27eaaf084263bb7d38de1621449e4e22a1b49dd8 Mon Sep 17 00:00:00 2001 From: Martin Sura Date: Tue, 7 May 2019 16:15:31 +0200 Subject: [PATCH 11/22] Add unknown option --- check_http_json.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/check_http_json.py b/check_http_json.py index dac67ec..8701f21 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -224,6 +224,12 @@ class JsonRuleProcessor: failure += self.checkExists(self.rules.key_list_critical) return failure + def checkUnknown(self): + unknown = '' + if self.rules.key_value_list_unknown != None: + unknown += self.checkEquality(self.rules.key_value_list_unknown) + return unknown + def checkMetrics(self): """Return a Nagios specific performance metrics string given keys and parameter definitions""" metrics = '' @@ -291,6 +297,8 @@ def parseArgs(): Multiple key values can be delimited with colon (key,value1:value2). Return warning if equality check fails') parser.add_argument('-Q', '--key_equals_critical', dest='key_value_list_critical', nargs='*', help='Same as -q but return critical if equality check fails.') + parser.add_argument('-u', '--key_equals_unknown', dest='key_value_list_unknown', nargs='*', + help='Same as -q but return unknown if equality check fails.') parser.add_argument('-m', '--key_metric', dest='metric_list', nargs='*', help='Gathers the values of these keys (key[>alias],UnitOfMeasure,WarnRange,CriticalRange,Min,Max) for Nagios performance data.\ More information about Range format and units of measure for nagios can be found at nagios-plugins.org/doc/guidelines.html\ @@ -437,6 +445,7 @@ if __name__ == "__main__": nagios.append_warning(processor.checkWarning()) nagios.append_critical(processor.checkCritical()) nagios.append_metrics(processor.checkMetrics()) + nagios.append_unknown(processor.checkUnknown()) # Print Nagios specific string and exit appropriately print nagios.getMessage() exit(nagios.getCode()) From 81522fa9ab6a416a956ed7fc9408d46afe57ebcb Mon Sep 17 00:00:00 2001 From: Martin Sura Date: Tue, 7 May 2019 16:23:48 +0200 Subject: [PATCH 12/22] fix intedation --- check_http_json.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check_http_json.py b/check_http_json.py index 8701f21..be4a6f7 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -227,8 +227,8 @@ class JsonRuleProcessor: def checkUnknown(self): unknown = '' if self.rules.key_value_list_unknown != None: - unknown += self.checkEquality(self.rules.key_value_list_unknown) - return unknown + unknown += self.checkEquality(self.rules.key_value_list_unknown) + return unknown def checkMetrics(self): """Return a Nagios specific performance metrics string given keys and parameter definitions""" From 3a108aef5e1390cf1d8e1b9fd82fdf20323464f4 Mon Sep 17 00:00:00 2001 From: luban8 <44843692+luban8@users.noreply.github.com> Date: Tue, 7 May 2019 16:25:00 +0200 Subject: [PATCH 13/22] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 63c06c5..a0d05cb 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ optional arguments: -Q [KEY_VALUE_LIST_CRITICAL [KEY_VALUE_LIST_CRITICAL ...]], --key_equals_critical [KEY_VALUE_LIST_CRITICAL [KEY_VALUE_LIST_CRITICAL ...]] Same as -q but return critical if equality check fails. + -u Same as -Q but return critical if equality check + fails. -m [METRIC_LIST [METRIC_LIST ...]], --key_metric [METRIC_LIST [METRIC_LIST ...]] Gathers the values of these keys (key[>alias],UnitOfMe asure,WarnRange,CriticalRange,Min,Max) for Nagios From cbdb884dc77586448118a05f3cd28f701fbd5657 Mon Sep 17 00:00:00 2001 From: luban8 <44843692+luban8@users.noreply.github.com> Date: Tue, 7 May 2019 16:27:56 +0200 Subject: [PATCH 14/22] Update README.md --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a0d05cb..c409ef5 100644 --- a/README.md +++ b/README.md @@ -70,10 +70,9 @@ optional arguments: (key,value1:value2). Return warning if equality check fails -Q [KEY_VALUE_LIST_CRITICAL [KEY_VALUE_LIST_CRITICAL ...]], --key_equals_critical [KEY_VALUE_LIST_CRITICAL [KEY_VALUE_LIST_CRITICAL ...]] - Same as -q but return critical if equality check - fails. - -u Same as -Q but return critical if equality check - fails. + Same as -q but return critical if equality check fails. + -u [KEY_VALUE_LIST_UNKNOWN [KEY_VALUE_LIST_UNKNOWN --key_equals_unknown [KEY_VALUE_LIST_UNKNOWN [KEY_VALUE_LIST_UNKNOWN ...]] + Same as -Q but return unknown if equality check fails. -m [METRIC_LIST [METRIC_LIST ...]], --key_metric [METRIC_LIST [METRIC_LIST ...]] Gathers the values of these keys (key[>alias],UnitOfMe asure,WarnRange,CriticalRange,Min,Max) for Nagios From 95318954bf50a43c6f8b575e2d249dbeecdf407d Mon Sep 17 00:00:00 2001 From: Ricardo Bartels Date: Thu, 9 May 2019 11:58:50 +0200 Subject: [PATCH 15/22] fixed indentation and and print statements * clean up from previous merges --- check_http_json.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/check_http_json.py b/check_http_json.py index 2fbeddb..2cca056 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -65,8 +65,8 @@ class NagiosHelper: def append_unknown(self, unknown_message): self.unknown_message += unknown_message - def append_metrics(self, (performance_data, - warning_message, critical_message)): + def append_metrics(self, performance_data, + warning_message, critical_message): self.performance_data += performance_data self.append_warning(warning_message) self.append_critical(critical_message) @@ -307,9 +307,9 @@ class JsonRuleProcessor: def checkUnknown(self): unknown = '' - if self.rules.key_value_list_unknown != None: + if self.rules.key_value_list_unknown is not None: unknown += self.checkEquality(self.rules.key_value_list_unknown) - return unknown + return unknown def checkMetrics(self): """Return a Nagios specific performance metrics string given keys @@ -432,7 +432,7 @@ def debugPrint(debug_flag, message, pretty_flag=False): if pretty_flag: pprint(message) else: - print message + print(message) if __name__ == "__main__" and len(sys.argv) >= 2 and sys.argv[1] == 'UnitTest': import unittest @@ -658,5 +658,5 @@ if __name__ == "__main__": nagios.append_metrics(processor.checkMetrics()) nagios.append_unknown(processor.checkUnknown()) # Print Nagios specific string and exit appropriately - print nagios.getMessage() + print(nagios.getMessage()) exit(nagios.getCode()) From 823fc275c944aaa063f4474c94cbf8c6669c94d3 Mon Sep 17 00:00:00 2001 From: Ricardo Bartels Date: Thu, 9 May 2019 13:18:34 +0200 Subject: [PATCH 16/22] fixed expansion on newly merged command line args --- check_http_json.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/check_http_json.py b/check_http_json.py index e624a7f..3c01161 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -206,10 +206,16 @@ class JsonRuleProcessor: self.key_threshold_critical = self.expandKeys( self.rules.key_threshold_critical) self.key_value_list = self.expandKeys(self.rules.key_value_list) + self.key_value_list_not = self.expandKeys( + self.rules.key_value_list_not) self.key_list = self.expandKeys(self.rules.key_list) self.key_value_list_critical = self.expandKeys( self.rules.key_value_list_critical) + self.key_value_list_not_critical = self.expandKeys( + self.rules.key_value_list_not_critical) self.key_list_critical = self.expandKeys(self.rules.key_list_critical) + self.key_value_list_unknown = self.expandKeys( + self.rules.key_value_list_unknown) def expandKeys(self, src): if src is None: @@ -302,8 +308,8 @@ class JsonRuleProcessor: failure += self.checkThresholds(self.key_threshold_warning) if self.key_value_list is not None: failure += self.checkEquality(self.key_value_list) - if self.rules.key_value_list_not is not None: - failure += self.checkNonEquality(self.rules.key_value_list_not) + if self.key_value_list_not is not None: + failure += self.checkNonEquality(self.key_value_list_not) if self.key_list is not None: failure += self.checkExists(self.key_list) return failure @@ -314,16 +320,16 @@ class JsonRuleProcessor: failure += self.checkThresholds(self.key_threshold_critical) if self.key_value_list_critical is not None: failure += self.checkEquality(self.key_value_list_critical) - if self.rules.key_value_list_not_critical is not None: - failure += self.checkNonEquality(self.rules.key_value_list_not_critical) + if self.key_value_list_not_critical is not None: + failure += self.checkNonEquality(self.key_value_list_not_critical) if self.key_list_critical is not None: failure += self.checkExists(self.key_list_critical) return failure def checkUnknown(self): unknown = '' - if self.rules.key_value_list_unknown is not None: - unknown += self.checkEquality(self.rules.key_value_list_unknown) + if self.key_value_list_unknown is not None: + unknown += self.checkEquality(self.key_value_list_unknown) return unknown def checkMetrics(self): @@ -402,7 +408,7 @@ def parseArgs(): parser.add_argument('-A', '--headers', dest='headers', help='The http headers in JSON format.') parser.add_argument('-f', '--field_separator', dest='separator', - help='''JSON Field separator, defaults to "." ; + help='''JSON Field separator, defaults to "."; Select element in an array with "(" ")"''') parser.add_argument('-w', '--warning', dest='key_threshold_warning', nargs='*', From 8437c464e539665984ca816ef694f29bed916750 Mon Sep 17 00:00:00 2001 From: Ricardo Bartels Date: Thu, 9 May 2019 14:55:25 +0200 Subject: [PATCH 17/22] refine ssl insecure and client certificate options * default TLS Protocols are now set to >= TLS1 * --cacert and --cert are no longer mandatory if option -s is used * proper error messages if parsing of cert or key files fails --- check_http_json.py | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/check_http_json.py b/check_http_json.py index 67355b4..64a8748 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -390,12 +390,8 @@ def parseArgs(): parser.add_argument('-k', '--insecure', action='store_true', help='do not check server SSL certificate') parser.add_argument('--cacert', - required=('-s' in sys.argv or '--ssl' in sys.argv) - and not ('-k' in sys.argv or '--insecure' in sys.argv), dest='cacert', help='SSL CA certificate') parser.add_argument('--cert', - required=('-s' in sys.argv or '--ssl' in sys.argv) - and not ('-k' in sys.argv or '--insecure' in sys.argv), dest='cert', help='SSL client certificate') parser.add_argument('--key', dest='key', help='SSL client key ( if not bundled into the cert )') @@ -680,13 +676,40 @@ if __name__ == "__main__": nagios = NagiosHelper() if args.ssl: url = "https://%s" % args.host + + context = ssl.SSLContext(ssl.PROTOCOL_TLS) + context.options |= ssl.OP_NO_SSLv2 + context.options |= ssl.OP_NO_SSLv3 + if args.insecure: - context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + context.verify_mode = ssl.CERT_NONE else: - context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) context.verify_mode = ssl.CERT_OPTIONAL - context.load_verify_locations(args.cacert) - context.load_cert_chain(args.cert,keyfile=args.key) + if args.cacert: + try: + context.load_verify_locations(args.cacert) + except ssl.SSLError: + nagios.append_unknown( + ''' Error loading SSL CA cert "%s"!''' + % args.cacert) + + if args.cert: + try: + context.load_cert_chain(args.cert,keyfile=args.key) + except ssl.SSLError: + if args.key: + nagios.append_unknown( + ''' Error loading SSL cert. Make sure key "%s" belongs to cert "%s"!''' + % (args.key, args.cert)) + else: + nagios.append_unknown( + ''' Error loading SSL cert. Make sure "%s" contains the key as well!''' + % (args.cert)) + + if nagios.getCode() != OK_CODE: + print(nagios.getMessage()) + exit(nagios.getCode()) + else: url = "http://%s" % args.host if args.port: From d98d0396b2885f23756cb6ea3ba2f2581401a194 Mon Sep 17 00:00:00 2001 From: Ricardo Bartels Date: Thu, 9 May 2019 15:06:52 +0200 Subject: [PATCH 18/22] return more meaningful error message if parsing of data failed --- check_http_json.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/check_http_json.py b/check_http_json.py index 64a8748..8872206 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -738,12 +738,16 @@ if __name__ == "__main__": else: response = urllib2.urlopen(req, context=context) except HTTPError as e: - nagios.append_unknown("HTTPError[%s], url:%s" % (str(e.code), url)) + 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)) + nagios.append_critical(" URLError[%s], url:%s" % (str(e.reason), url)) + + try: + data = json.loads(response.read()) + except ValueError as e: + nagios.append_unknown(" Parser error: %s" % str(e)) + else: - jsondata = response.read() - data = json.loads(jsondata) debugPrint(args.debug, 'json:') debugPrint(args.debug, data, True) # Apply rules to returned JSON data @@ -752,6 +756,9 @@ if __name__ == "__main__": nagios.append_critical(processor.checkCritical()) nagios.append_metrics(processor.checkMetrics()) nagios.append_unknown(processor.checkUnknown()) + # Print Nagios specific string and exit appropriately print(nagios.getMessage()) exit(nagios.getCode()) + +#EOF From bcc36a6e95b6e16d5d4c659a6097e870aeace98e Mon Sep 17 00:00:00 2001 From: Ricardo Bartels Date: Thu, 9 May 2019 15:44:33 +0200 Subject: [PATCH 19/22] added version information and improved help text --- check_http_json.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/check_http_json.py b/check_http_json.py index 8872206..33b2bd4 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -1,5 +1,6 @@ #!/usr/bin/python2.7 +plugin_description = \ """ Check HTTP JSON Nagios Plugin @@ -23,6 +24,8 @@ WARNING_CODE = 1 CRITICAL_CODE = 2 UNKNOWN_CODE = 3 +__version__ = '1.4.0' +__version_date__ = '2019-05-09' class NagiosHelper: """Help with Nagios specific status string formatting.""" @@ -378,17 +381,22 @@ class JsonRuleProcessor: def parseArgs(): - parser = argparse.ArgumentParser(description='''Nagios plugin which - checks json values from a given endpoint against argument specified rules - and determines the status and performance data for that service''') + parser = argparse.ArgumentParser( + description = plugin_description + '\n\nVersion: %s (%s)' + %(__version__, __version_date__), + formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument('-d', '--debug', action='store_true', - help='Debug mode.') - parser.add_argument('-s', '--ssl', action='store_true', help='HTTPS mode.') - parser.add_argument('-H', '--host', dest='host', required=True, - help='Host.') + help='debug mode') + 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), + help='remote host to query') parser.add_argument('-k', '--insecure', action='store_true', help='do not check server SSL certificate') + parser.add_argument('-V', '--version', action='store_true', + help='print version of this plugin') parser.add_argument('--cacert', dest='cacert', help='SSL CA certificate') parser.add_argument('--cert', @@ -396,7 +404,7 @@ def parseArgs(): parser.add_argument('--key', dest='key', help='SSL client key ( if not bundled into the cert )') parser.add_argument('-P', '--port', dest='port', help='TCP port') - parser.add_argument('-p', '--path', dest='path', help='Path.') + parser.add_argument('-p', '--path', dest='path', help='Path') parser.add_argument('-t', '--timeout', type=int, help='Connection timeout (seconds)') parser.add_argument('-B', '--basic-auth', dest='auth', @@ -674,6 +682,10 @@ if __name__ == "__main__" and len(sys.argv) >= 2 and sys.argv[1] == 'UnitTest': if __name__ == "__main__": args = parseArgs() nagios = NagiosHelper() + if args.version: + print('Version: %s - Date: %s' % (__version__, __version_date__)) + exit(0) + if args.ssl: url = "https://%s" % args.host From 1173420803ccb78b2cb75a64f3b074ab2d1fe534 Mon Sep 17 00:00:00 2001 From: Ricardo Bartels Date: Thu, 9 May 2019 15:48:29 +0200 Subject: [PATCH 20/22] updated README with current cli options --- README.md | 63 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index c409ef5..b021554 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,8 @@ This is a generic plugin for Nagios which checks json values from a given HTTP e Executing `./check_http_json.py -h` will yield the following details: ``` -usage: check_http_json.py [-h] [-d] [-s] -H HOST [-P PORT] [-p PATH] +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] [-w [KEY_THRESHOLD_WARNING [KEY_THRESHOLD_WARNING ...]]] @@ -24,19 +25,31 @@ usage: check_http_json.py [-h] [-d] [-s] -H HOST [-P PORT] [-p PATH] [-E [KEY_LIST_CRITICAL [KEY_LIST_CRITICAL ...]]] [-q [KEY_VALUE_LIST [KEY_VALUE_LIST ...]]] [-Q [KEY_VALUE_LIST_CRITICAL [KEY_VALUE_LIST_CRITICAL ...]]] + [-u [KEY_VALUE_LIST_UNKNOWN [KEY_VALUE_LIST_UNKNOWN ...]]] + [-y [KEY_VALUE_LIST_NOT [KEY_VALUE_LIST_NOT ...]]] + [-Y [KEY_VALUE_LIST_NOT_CRITICAL [KEY_VALUE_LIST_NOT_CRITICAL ...]]] [-m [METRIC_LIST [METRIC_LIST ...]]] -Nagios plugin which checks json values from a given endpoint against argument -specified rules and determines the status and performance data for that -service +Check HTTP JSON Nagios Plugin + +Generic Nagios plugin which checks json values from a given endpoint against +argument specified rules and determines the status and performance data for +that service. + +Version: 1.4.0 (2019-05-09) optional arguments: -h, --help show this help message and exit - -d, --debug Debug mode. - -s, --ssl HTTPS mode. - -H HOST, --host HOST Host. + -d, --debug debug mode + -s, --ssl use TLS to connect to remote host + -H HOST, --host HOST remote host to query + -k, --insecure do not check server SSL certificate + -V, --version print version of this plugin + --cacert CACERT SSL CA certificate + --cert CERT SSL client certificate + --key KEY SSL client key ( if not bundled into the cert ) -P PORT, --port PORT TCP port - -p PATH, --path PATH Path. + -p PATH, --path PATH Path -t TIMEOUT, --timeout TIMEOUT Connection timeout (seconds) -B AUTH, --basic-auth AUTH @@ -45,7 +58,7 @@ optional arguments: -A HEADERS, --headers HEADERS The http headers in JSON format. -f SEPARATOR, --field_separator SEPARATOR - Json Field separator, defaults to "." ; Select element + JSON Field separator, defaults to "."; Select element in an array with "(" ")" -w [KEY_THRESHOLD_WARNING [KEY_THRESHOLD_WARNING ...]], --warning [KEY_THRESHOLD_WARNING [KEY_THRESHOLD_WARNING ...]] Warning threshold for these values @@ -70,18 +83,28 @@ optional arguments: (key,value1:value2). Return warning if equality check fails -Q [KEY_VALUE_LIST_CRITICAL [KEY_VALUE_LIST_CRITICAL ...]], --key_equals_critical [KEY_VALUE_LIST_CRITICAL [KEY_VALUE_LIST_CRITICAL ...]] - Same as -q but return critical if equality check fails. - -u [KEY_VALUE_LIST_UNKNOWN [KEY_VALUE_LIST_UNKNOWN --key_equals_unknown [KEY_VALUE_LIST_UNKNOWN [KEY_VALUE_LIST_UNKNOWN ...]] - Same as -Q but return unknown if equality check fails. + Same as -q but return critical if equality check + fails. + -u [KEY_VALUE_LIST_UNKNOWN [KEY_VALUE_LIST_UNKNOWN ...]], --key_equals_unknown [KEY_VALUE_LIST_UNKNOWN [KEY_VALUE_LIST_UNKNOWN ...]] + Same as -q but return unknown if equality check fails. + -y [KEY_VALUE_LIST_NOT [KEY_VALUE_LIST_NOT ...]], --key_not_equals [KEY_VALUE_LIST_NOT [KEY_VALUE_LIST_NOT ...]] + 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 + -Y [KEY_VALUE_LIST_NOT_CRITICAL [KEY_VALUE_LIST_NOT_CRITICAL ...]], --key_not_equals_critical [KEY_VALUE_LIST_NOT_CRITICAL [KEY_VALUE_LIST_NOT_CRITICAL ...]] + Same as -q but return critical if equality check + succeeds. -m [METRIC_LIST [METRIC_LIST ...]], --key_metric [METRIC_LIST [METRIC_LIST ...]] - Gathers the values of these keys (key[>alias],UnitOfMe - asure,WarnRange,CriticalRange,Min,Max) for Nagios - performance data. More information about Range format - and units of measure for nagios can be found at + Gathers the values of these keys (key[>alias], + UnitOfMeasure,WarnRange,CriticalRange,Min,Max) for + Nagios performance data. More information about Range + format and units of measure for nagios can be found at nagios-plugins.org/doc/guidelines.html Additional formats for this parameter are: (key[>alias]), (key[>alias],UnitOfMeasure), - (key[>alias],UnitOfMeasure,WarnRange,CriticalRange). + (key[>alias],UnitOfMeasure,WarnRange, CriticalRange). ``` ## Examples @@ -143,7 +166,7 @@ optional arguments: * **Warning:** `./check_http_json.py -H : -p -w "metric,RANGE"` * **Critical:** `./check_http_json.py -H : -p -c "metric,RANGE"` * **Metrics with Warning:** `./check_http_json.py -H : -p -w "metric,RANGE"` -* **Metris with Critical:** +* **Metrics with Critical:** ./check_http_json.py -H : -p -w "metric,,,RANGE" ./check_http_json.py -H : -p -w "metric,,,,MIN,MAX" @@ -160,7 +183,7 @@ optional arguments: More info about Nagios Range format and Units of Measure can be found at [https://nagios-plugins.org/doc/guidelines.html](https://nagios-plugins.org/doc/guidelines.html). -#### Using Headers +#### Using Headers * `./check_http_json.py -H : -p -A '{"content-type": "application/json"}' -w "metric,RANGE"` @@ -168,7 +191,7 @@ More info about Nagios Range format and Units of Measure can be found at [https: ### Requirements -* Python +* Python 2.7 ### Configuration From 7858382bbed7b83f77457faa36b4f5e3f0331b54 Mon Sep 17 00:00:00 2001 From: Ricardo Bartels Date: Thu, 9 May 2019 15:53:59 +0200 Subject: [PATCH 21/22] Added default User-Agent header * prevent errors for services which require this header (like Cloudflare WAF) --- check_http_json.py | 1 + 1 file changed, 1 insertion(+) diff --git a/check_http_json.py b/check_http_json.py index 33b2bd4..bc7b14f 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -731,6 +731,7 @@ if __name__ == "__main__": debugPrint(args.debug, "url:%s" % url) try: req = urllib2.Request(url) + req.add_header("User-Agent", "check_http_json") if args.auth: base64str = base64.encodestring(args.auth).replace('\n', '') req.add_header('Authorization', 'Basic %s' % base64str) From 47547951cfa03b708340fed23710cb78a7685663 Mon Sep 17 00:00:00 2001 From: Ricardo Bartels Date: Thu, 9 May 2019 16:39:41 +0200 Subject: [PATCH 22/22] fixed minor bugs and added compatibility for RHEL/CentOS 7.x * change ssl.PROTOCOL_TLS to ssl.PROTOCOL_SSLv23 * fixed bug that response var not passed outside try/except block * fixed arrer in nagios.append_metrics() --- check_http_json.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/check_http_json.py b/check_http_json.py index bc7b14f..c5b7960 100755 --- a/check_http_json.py +++ b/check_http_json.py @@ -69,8 +69,8 @@ class NagiosHelper: def append_unknown(self, unknown_message): self.unknown_message += unknown_message - def append_metrics(self, performance_data, - warning_message, critical_message): + def append_metrics(self, (performance_data, + warning_message, critical_message)): self.performance_data += performance_data self.append_warning(warning_message) self.append_critical(critical_message) @@ -689,7 +689,7 @@ if __name__ == "__main__": if args.ssl: url = "https://%s" % args.host - context = ssl.SSLContext(ssl.PROTOCOL_TLS) + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) context.options |= ssl.OP_NO_SSLv2 context.options |= ssl.OP_NO_SSLv3 @@ -729,6 +729,7 @@ if __name__ == "__main__": if args.path: url += "/%s" % args.path debugPrint(args.debug, "url:%s" % url) + json_data = '' try: req = urllib2.Request(url) req.add_header("User-Agent", "check_http_json") @@ -750,13 +751,16 @@ if __name__ == "__main__": response = urllib2.urlopen(req, data=args.data, context=context) else: response = urllib2.urlopen(req, context=context) + + json_data = response.read() + except HTTPError as e: 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)) try: - data = json.loads(response.read()) + data = json.loads(json_data) except ValueError as e: nagios.append_unknown(" Parser error: %s" % str(e))