def __init__(self): self._long_output = [] self._summary = [] self.thresholds = [] self._perfdata = PerfData() # Performance and Threshold Metrics are stored here self.parser = OptionParser() general = OptionGroup(self.parser, "Generic Options") self.parser.add_option('--threshold','--th',default=[], help="Thresholds in standard nagios threshold format", metavar='', dest="thresholds",action="append") display_group = OptionGroup(self.parser, "Display Options") display_group.add_option("-v", "--verbose", dest="verbose", help="Print more verbose info", metavar="v", action="store_true", default=self.verbose) general.add_option("-d", "--debug", dest="show_debug", help="Print debug info", metavar="d", action="store_true", default=self.show_debug) display_group.add_option("--no-perfdata", dest="show_perfdata", help="Dont show any performance data", action="store_false", default=self.show_perfdata) display_group.add_option("--no-longoutput", dest="show_longoutput", help="Hide longoutput from the plugin output (i.e. only display first line of the output)", action="store_false", default=self.show_longoutput) display_group.add_option("--no-summary", dest="show_summary", help="Hide summary from plugin output", action="store_false", default=self.show_summary) #display_group.add_option("--show-status-in-summary", dest="show_status_in_summary", help="Prefix the summary of the plugin with OK- or WARN- ", action="store_true", default=False) display_group.add_option("--get-metrics", dest="get_metrics", help="Print all available metrics and exit (can be combined with --verbose)", action="store_true", default=False) display_group.add_option("--legacy", dest="show_legacy", help="Output perfdata in legacy format", action="store_true", default=self.show_legacy) self.parser.add_option_group(display_group)
class PluginHelper: """ PluginHelper takes away some of the tedious work of writing Nagios plugins. Primary features include: * Keep a collection of your plugin messages (queue for both summary and longoutput) * Keep record of exit status * Keep a collection of your metrics (for both perfdata and thresholds) * Automatic Command-line arguments * Make sure output of your plugin is within Plugin Developer Guidelines Usage: p = PluginHelper() p.status(warning) p.add_summary('Example Plugin with warning status') p.add_metric('cpu load', '90') p.exit() """ _nagios_status = -1 # exit status of the plugin _long_output = None # Long output of the plugin _summary = None # Summary of the plugin _perfdata = None # Performance and Threshold Metrics are stored here show_longoutput = True # If True, print longoutput show_perfdata = True # If True, print perfdata show_summary = True # If True, print Summary show_status_in_summary = True show_legacy = False # If True, print perfdata in legacy form verbose = False # Extra verbosity show_debug = False # Extra debugging timeout = 50 # Default timeout set to little less than nagios service check timeout thresholds = None # List of strings in the nagios threshold format options = None # OptionParser() options arguments = None # OptionParser() arguments def __init__(self): self._long_output = [] self._summary = [] self.thresholds = [] self._perfdata = PerfData() # Performance and Threshold Metrics are stored here self.parser = OptionParser() general = OptionGroup(self.parser, "Generic Options") self.parser.add_option('--threshold','--th',default=[], help="Thresholds in standard nagios threshold format", metavar='', dest="thresholds",action="append") display_group = OptionGroup(self.parser, "Display Options") display_group.add_option("-v", "--verbose", dest="verbose", help="Print more verbose info", metavar="v", action="store_true", default=self.verbose) general.add_option("-d", "--debug", dest="show_debug", help="Print debug info", metavar="d", action="store_true", default=self.show_debug) display_group.add_option("--no-perfdata", dest="show_perfdata", help="Dont show any performance data", action="store_false", default=self.show_perfdata) display_group.add_option("--no-longoutput", dest="show_longoutput", help="Hide longoutput from the plugin output (i.e. only display first line of the output)", action="store_false", default=self.show_longoutput) display_group.add_option("--no-summary", dest="show_summary", help="Hide summary from plugin output", action="store_false", default=self.show_summary) #display_group.add_option("--show-status-in-summary", dest="show_status_in_summary", help="Prefix the summary of the plugin with OK- or WARN- ", action="store_true", default=False) display_group.add_option("--get-metrics", dest="get_metrics", help="Print all available metrics and exit (can be combined with --verbose)", action="store_true", default=False) display_group.add_option("--legacy", dest="show_legacy", help="Output perfdata in legacy format", action="store_true", default=self.show_legacy) self.parser.add_option_group(display_group) def parse_arguments(self, argument_list=None): """ Parsers commandline arguments, prints error if there is a syntax error. Creates: self.options -- As created by OptionParser.parse() self.arguments -- As created by OptionParser.parse() Arguments: argument_list -- By default use sys.argv[1:], override only if you know what you are doing. Returns: None """ self.options, self.arguments = self.parser.parse_args(args=argument_list) # TODO: Handle it if developer decides to remove some options before calling parse_arguments() self.thresholds = self.options.thresholds self.show_longoutput = self.options.show_longoutput self.show_perfdata = self.options.show_perfdata self.show_legacy = self.options.show_legacy self.show_debug = self.options.show_debug self.verbose = self.options.verbose #self.show_status_in_summary = self.options.show_status_in_summary def add_long_output(self, message): """ Appends message to the end of Plugin long_output. Message does not need a \n suffix Examples: >>> p = PluginHelper() >>> p.add_long_output('Status of sensor 1') >>> p.add_long_output('* Temperature: OK') >>> p.add_long_output('* Humidity: OK') >>> p.get_long_output() 'Status of sensor 1\\n* Temperature: OK\\n* Humidity: OK' """ self._long_output.append(message) def add_option(self, *args, **kwargs): """ Same as self.parser.add_option() """ return self.parser.add_option(*args,**kwargs) def get_long_output(self): """ Returns all long_output that has been added via add_long_output """ return '\n'.join(self._long_output) def set_long_output(self, message): """ Overwrite current long_output with message Example: >>> s = PluginHelper() >>> s.add_long_output('first long output') >>> s.set_long_output('Fatal error') >>> s.get_long_output() 'Fatal error' """ self._long_output = [message] def add_summary(self, message): """ Adds message to Plugin Summary """ self._summary.append(message.strip()) def set_summary(self, message): """ Overwrite current summary with message Example: >>> s = PluginHelper() >>> s.add_summary('first summary') >>> s.set_summary('Fatal error') >>> s.get_summary() 'Fatal error' """ self._summary = [message] def get_summary(self): return '. '.join(self._summary) def get_status(self): """ Returns the worst nagios status (integer 0,1,2,3) that has been put with add_status() If status has never been added, returns 3 for UNKNOWN """ # If no status has been set, return unknown if self._nagios_status == -1: return UNKNOWN else: return self._nagios_status def status(self, new_status=None): """ Same as get_status() if new_status=None, otherwise call add_status(new_status) """ if new_status is None: return self.get_status() if new_status not in state_text: new_status = unknown return self.add_status(new_status) def add_status(self, new_status=None): """ Update exit status of the nagios plugin. This function will keep history of the worst status added Examples: >>> p = PluginHelper() >>> p.add_status(0) # ok >>> p.add_status(2) # critical >>> p.add_status(1) # warning >>> p.get_status() # 2 >>> p = PluginHelper() >>> p.add_status('warning') >>> p.add_status('ok') >>> p.get_status() 1 >>> p.add_status('okay') Traceback (most recent call last): ... Exception: Invalid status supplied "okay" """ # If new status was entered as a human readable string (ok,warn,etc) lets convert it to int: if type(new_status) == type(''): if new_status.lower() in state: new_status = state[new_status] else: raise Exception("Invalid status supplied \"%s\"" % (new_status)) self._nagios_status = max(self._nagios_status, new_status) def add_metric(self, label="",value="",warn="",crit="",min="",max="",uom="", perfdatastring=None): """ Add numerical metric (will be outputted as nagios performanca data) Examples: >>> p = PluginHelper() >>> p.add_metric(label="load1", value="7") >>> p.add_metric(label="load5", value="5") >>> p.add_metric(label="load15",value="2") >>> p.get_perfdata() "'load1'=7;;;; 'load5'=5;;;; 'load15'=2;;;;" >>> p = PluginHelper() >>> p.add_metric(perfdatastring="load1=6;;;;") >>> p.add_metric(perfdatastring="load5=4;;;;") >>> p.add_metric(perfdatastring="load15=1;;;;") >>> p.get_perfdata() "'load1'=6;;;; 'load5'=4;;;; 'load15'=1;;;;" """ if not perfdatastring is None: self._perfdata.add_perfdatametric(perfdatastring=perfdatastring) else: self._perfdata.add_perfdatametric(label=label,value=value,warn=warn,crit=crit,min=min,max=max,uom=uom) def get_metric(self, label): """ Return one specific metric (PerfdataMetric object) with the specified label. Returns None if not found. Example: >>> p = PluginHelper() >>> p.add_metric(label="load1", value="7") >>> p.add_metric(label="load15",value="2") >>> p.get_metric("load1") 'load1'=7;;;; >>> p.get_metric("unknown") # Returns None """ for i in self._perfdata.metrics: if i.label == label: return i return None def convert_perfdata(self, perfdata): """ Converts new threshold range format to old one. Returns None. Examples: x..y -> x:y inf..y -> :y -inf..y -> :y x..inf -> x: -inf..inf -> : """ for metric in perfdata: metric.warn = metric.warn.replace("..",":").replace("-inf","").replace("inf","") metric.crit = metric.crit.replace("..",":").replace("-inf","").replace("inf","") return None def get_perfdata(self): """ Get perfdatastring for all valid perfdatametrics collected via add_perfdata Examples: >>> p = PluginHelper() >>> p.add_metric(label="load1", value="7", warn="-inf..10", crit="10..inf") >>> p.add_metric(label="load5", value="5", warn="-inf..7", crit="7..inf") >>> p.add_metric(label="load15",value="2", warn="-inf..5", crit="5..inf") >>> p.get_perfdata() "'load1'=7;-inf..10;10..inf;; 'load5'=5;-inf..7;7..inf;; 'load15'=2;-inf..5;5..inf;;" Example with legacy output (show_legacy should be set with a cmdline option): >>> p.show_legacy = True >>> p.get_perfdata() "'load1'=7;:10;10:;; 'load5'=5;:7;7:;; 'load15'=2;:5;5:;;" """ if self.show_legacy == True: self.convert_perfdata(self._perfdata.metrics) return str(self._perfdata ) def get_plugin_output(self, exit_code=None,summary=None, long_output=None, perfdata=None): """ Get all plugin output as it would be printed to screen with self.exit() Examples of functionality: >>> p = PluginHelper() >>> p.get_plugin_output() 'Unknown -' >>> p = PluginHelper() >>> p.add_summary('Testing') >>> p.add_long_output('Long testing output') >>> p.add_long_output('More output') >>> p.get_plugin_output(exit_code=0) 'OK - Testing\\nLong testing output\\nMore output' >>> p = PluginHelper() >>> p.add_summary('Testing') >>> p.add_status(0) >>> p.get_plugin_output() 'OK - Testing' >>> p = PluginHelper() >>> p.show_status_in_summary = False >>> p.add_summary('Testing') >>> p.add_metric(label="load1", value="7") >>> p.add_metric(label="load5", value="5") >>> p.add_metric(label="load15",value="2") >>> p.get_plugin_output(exit_code=0) "Testing | 'load1'=7;;;; 'load5'=5;;;; 'load15'=2;;;;" >>> p = PluginHelper() >>> p.show_status_in_summary = False >>> p.add_summary('Testing') >>> p.add_long_output('Long testing output') >>> p.add_long_output('More output') >>> p.add_metric(label="load1", value="7") >>> p.add_metric(label="load5", value="5") >>> p.add_metric(label="load15",value="2") >>> p.get_plugin_output(exit_code=0) "Testing | 'load1'=7;;;; 'load5'=5;;;; 'load15'=2;;;;\\nLong testing output\\nMore output" """ if summary is None: summary = self.get_summary() if long_output is None: long_output = self.get_long_output() if perfdata is None: perfdata = self.get_perfdata() if exit_code is None: exit_code = self.get_status() return_buffer = "" if self.show_status_in_summary == True: return_buffer += "%s - " % state_text[exit_code] if self.show_summary == True: return_buffer += summary if self.show_perfdata == True and len(perfdata) > 0: return_buffer += " | %s\n" % perfdata if not return_buffer.endswith('\n'): return_buffer += '\n' if self.show_longoutput == True and len(long_output) > 0: return_buffer += long_output return_buffer = return_buffer.strip() return return_buffer def exit(self, exit_code=None,summary=None, long_output=None, perfdata=None): """ Print all collected output to screen and exit nagios style, no arguments are needed except if you want to override default behavior. Arguments: summary -- Is this text as the plugin summary instead of self.get_summary() long_output -- Use this text as long_output instead of self.get_long_output() perfdata -- Use this text instead of self.get_perfdata() exit_code -- Use this exit code instead of self.status() """ if exit_code is None: exit_code = self.get_status() if self.options and self.options.get_metrics == True: summary = "Available metrics for this plugin:" metrics = [] for i in self._perfdata.metrics: if self.options.verbose == True: metrics.append( str(i) ) else: metrics.append( i.label ) long_output = '\n'.join(metrics) plugin_output = self.get_plugin_output(exit_code=exit_code,summary=summary,long_output=long_output,perfdata=perfdata) print plugin_output sys.exit(exit_code) def check_metric(self, metric_name, thresholds): """ Check one specific metric against a list of thresholds. Updates self.status() and writes to summary or longout as appropriate. Arguments: metric_name -- A string representing the name of the metric (the label part of the performance data) thresholds -- a list in the form of [ (level,range) ] where range is a string in the format of "start..end" Examples: >>> p = PluginHelper() >>> thresholds = [(warning,'2..5'), (critical,'5..inf')] >>> p.get_plugin_output() 'Unknown -' >>> p.add_metric('load15', '3') >>> p.check_metric('load15',thresholds) >>> p.get_plugin_output() "Warning - Warning on load15 | 'load15'=3;2..5;5..inf;;" >>> p = PluginHelper() >>> thresholds = [(warning,'2..5'), (critical,'5..inf')] >>> p.add_metric('load15', '3') >>> p.verbose = True >>> p.check_metric('load15',thresholds) >>> p.get_plugin_output() "Warning - Warning on load15 | 'load15'=3;2..5;5..inf;;\\nWarning on load15" Invalid metric: >>> p = PluginHelper() >>> p.add_status(ok) >>> p.add_summary('Everythings fine!') >>> p.get_plugin_output() 'OK - Everythings fine!' >>> thresholds = [(warning,'2..5'), (critical,'5..inf')] >>> p.check_metric('never_added_metric', thresholds) >>> p.get_plugin_output() 'Unknown - Everythings fine!. Metric never_added_metric not found' Invalid threshold: >>> p = PluginHelper() >>> thresholds = [(warning, 'invalid'), (critical,'5..inf')] >>> p.add_metric('load1', '10') >>> p.check_metric('load1', thresholds) Traceback (most recent call last): ... SystemExit: 3 Returns: None """ metric = self.get_metric(label=metric_name) # If threshold was specified but metric not found in our data, set status unknown if metric is None: self.status(unknown) self.add_summary("Metric %s not found" % (metric_name)) return metric_status = -1 # by default assume nothing default_state = 0 # By default if no treshold matches, we assume OK highest_level = ok # highest threshold range seen # Iterate through all thresholds, and log down warn and crit for perfdata purposes for level, threshold_range in thresholds: if metric.warn == '' and level == warning: metric.warn = threshold_range elif metric.crit == '' and level == critical: metric.crit = threshold_range if level == ok: default_state = 2 # Iterate all threshold and determine states for level, threshold_range in thresholds: highest_level = max(highest_level, level) # If ok threshold was specified, default state is critical according to spec # If value matches our threshold, we increment the status try: in_range = new_threshold_syntax.check_range(metric.value, threshold_range) except PynagError: self.set_summary( "Could not parse threshold %s=%s for metric %s" % (state_text[level], threshold_range, metric_name) ) self.set_long_output("Thresholds should be in the format metric=<metric_name>,ok=0..90,warning=90..95") self.add_long_output("Example: ") self.add_long_output("--th metric=load,ok=0..1,warning=1..5,critical=5..inf") self.status(unknown) self.exit() if in_range: metric_status = max(metric_status, level) self.debug('%s is within %s range "%s"' % (metric_name, state_text[level], threshold_range)) if level == ok: self.debug("OK threshold matches, not checking any more thresholds") metric_status = ok break else: self.debug('%s is outside %s range "%s"' % (metric_name, state_text[level],threshold_range)) # If no thresholds matched, set a default return code if metric_status < 0: metric_status = default_state # OK's go to long output, errors go directly to summary self.add_status(metric_status) message = '%s on %s' % (state_text[metric_status], metric_name) # Errors are added to the summary: if metric_status > 0: self.add_summary(message) if self.verbose == True: self.add_long_output(message) def check_all_metrics(self): """ Checks all metrics (add_metric() against any thresholds set in self.options.thresholds or with --threshold from commandline)""" checked_metrics = [] for threshold in self.thresholds: parsed_threshold = new_threshold_syntax.parse_threshold(threshold) metric_name = parsed_threshold['metric'] thresholds = parsed_threshold['thresholds'] self.check_metric(metric_name, thresholds) checked_metrics.append( metric_name ) # Lets look at metrics that were not specified on the command-line but might have a default # threshold specified with their metric data for i in self._perfdata.metrics: if i.label in checked_metrics: continue thresholds = [] if i.warn != '': thresholds.append( (warning, i.warn)) if i.crit != '': thresholds.append( (critical, i.crit)) self.check_metric(i.label, thresholds) def run_function(self, function, *args, **kwargs): """ Executes "function" and exits Nagios style with status "unkown" if there are any exceptions. The stacktrace will be in long_output. Example: >>> p = PluginHelper() >>> p.add_status('ok') >>> p.get_status() 0 >>> p.add_status('okay') Traceback (most recent call last): ... Exception: Invalid status supplied "okay" >>> p.run_function( p.add_status, 'warning' ) >>> p.get_status() 1 >>> p.run_function( p.add_status, 'okay' ) Traceback (most recent call last): ... SystemExit: 3 """ try: function(*args, **kwargs) except Exception, e: exc_type, exc_value, exc_traceback = sys.exc_info() exit_code = unknown #traceback.print_exc(file=sys.stdout) summary = "Unhandled '%s' exception while running plugin (traceback below)" % exc_type long_output = traceback.format_exc() self.exit(exit_code=exit_code, summary=summary, long_output=long_output,perfdata='')
def __init__(self): self._long_output = [] self._summary = [] self.thresholds = [] # Performance and Threshold Metrics are stored here self._perfdata = PerfData() self.parser = OptionParser() generic_group = OptionGroup(self.parser, "Generic Options") generic_group.add_option( '--timeout', help="Exit plugin with unknown status after x seconds", type='int', metavar='50', dest="timeout", default=self.timeout) generic_group.add_option( '--threshold', default=[], help="Thresholds in standard nagios threshold format", metavar='range', dest="thresholds", action="append") generic_group.add_option('--th', default=[], help="Same as --threshold", metavar='range', dest="thresholds", action="append") generic_group.add_option( '--extra-opts', help= "Read options from an ini file. See http://nagiosplugins.org/extra-opts", metavar='@file', dest="extra_opts") generic_group.add_option("-d", "--debug", dest="show_debug", help="Print debug info", metavar="d", action="store_true", default=self.show_debug) # Display options are options that affect the output of the plugin # But usually not its function display_group = OptionGroup(self.parser, "Display Options") display_group.add_option("-v", "--verbose", dest="verbose", help="Print more verbose info", metavar="v", action="store_true", default=self.verbose) display_group.add_option("--no-perfdata", dest="show_perfdata", help="Dont show any performance data", action="store_false", default=self.show_perfdata) display_group.add_option( "--no-longoutput", dest="show_longoutput", help= "Hide longoutput from the plugin output (i.e. only display first line of the output)", action="store_false", default=self.show_longoutput) display_group.add_option("--no-summary", dest="show_summary", help="Hide summary from plugin output", action="store_false", default=self.show_summary) display_group.add_option( "--get-metrics", dest="get_metrics", help= "Print all available metrics and exit (can be combined with --verbose)", action="store_true", default=False) display_group.add_option("--legacy", dest="show_legacy", help="Deprecated, do not use", action="store_true", default=self.show_legacy) self.parser.add_option_group(generic_group) self.parser.add_option_group(display_group)
class PluginHelper(object): """ PluginHelper takes away some of the tedious work of writing Nagios plugins. Primary features include: * Keep a collection of your plugin messages (queue for both summary and longoutput) * Keep record of exit status * Keep a collection of your metrics (for both perfdata and thresholds) * Automatic Command-line arguments * Make sure output of your plugin is within Plugin Developer Guidelines Usage: p = PluginHelper() p.status(warning) p.add_summary('Example Plugin with warning status') p.add_metric('cpu load', '90') p.exit() """ _nagios_status = -1 # exit status of the plugin _long_output = None # Long output of the plugin _summary = None # Summary of the plugin _perfdata = None # Performance and Threshold Metrics are stored here show_longoutput = True # If True, print longoutput show_perfdata = True # If True, print perfdata show_summary = True # If True, print Summary show_status_in_summary = True show_legacy = False # Deprecated, doesnt do anything verbose = False # Extra verbosity show_debug = False # Extra debugging # By default, plugins timeout right before nagios kills the plugin timeout = 58 thresholds = None # List of strings in the nagios threshold format options = None # OptionParser() options arguments = None # OptionParser() arguments def __init__(self): self._long_output = [] self._summary = [] self.thresholds = [] # Performance and Threshold Metrics are stored here self._perfdata = PerfData() self.parser = OptionParser() generic_group = OptionGroup(self.parser, "Generic Options") generic_group.add_option( '--timeout', help="Exit plugin with unknown status after x seconds", type='int', metavar='50', dest="timeout", default=self.timeout) generic_group.add_option( '--threshold', default=[], help="Thresholds in standard nagios threshold format", metavar='range', dest="thresholds", action="append") generic_group.add_option('--th', default=[], help="Same as --threshold", metavar='range', dest="thresholds", action="append") generic_group.add_option( '--extra-opts', help= "Read options from an ini file. See http://nagiosplugins.org/extra-opts", metavar='@file', dest="extra_opts") generic_group.add_option("-d", "--debug", dest="show_debug", help="Print debug info", metavar="d", action="store_true", default=self.show_debug) # Display options are options that affect the output of the plugin # But usually not its function display_group = OptionGroup(self.parser, "Display Options") display_group.add_option("-v", "--verbose", dest="verbose", help="Print more verbose info", metavar="v", action="store_true", default=self.verbose) display_group.add_option("--no-perfdata", dest="show_perfdata", help="Dont show any performance data", action="store_false", default=self.show_perfdata) display_group.add_option( "--no-longoutput", dest="show_longoutput", help= "Hide longoutput from the plugin output (i.e. only display first line of the output)", action="store_false", default=self.show_longoutput) display_group.add_option("--no-summary", dest="show_summary", help="Hide summary from plugin output", action="store_false", default=self.show_summary) display_group.add_option( "--get-metrics", dest="get_metrics", help= "Print all available metrics and exit (can be combined with --verbose)", action="store_true", default=False) display_group.add_option("--legacy", dest="show_legacy", help="Deprecated, do not use", action="store_true", default=self.show_legacy) self.parser.add_option_group(generic_group) self.parser.add_option_group(display_group) def parse_arguments(self, argument_list=None): """ Parsers commandline arguments, prints error if there is a syntax error. Creates: self.options -- As created by OptionParser.parse() self.arguments -- As created by OptionParser.parse() Arguments: argument_list -- By default use sys.argv[1:], override only if you know what you are doing. Returns: None """ self.options, self.arguments = self.parser.parse_args( args=argument_list) extra_opts = self.options.extra_opts if extra_opts is not None: # --extra-opts was specified if extra_opts == '': # --extra-opts= with no value. section_name = None config_file = None elif '@' in extra_opts: # filename was specified section_name, config_file = extra_opts.split('@', 1) else: # Only section was specified section_name = extra_opts config_file = None values = self.get_default_values(section_name, config_file) self.options, self.arguments = self.parser.parse_args( args=argument_list, values=values) # TODO: Handle it if developer decides to remove some options before # calling parse_arguments() self.thresholds = self.options.thresholds self.show_longoutput = self.options.show_longoutput self.show_perfdata = self.options.show_perfdata self.show_legacy = self.options.show_legacy self.show_debug = self.options.show_debug self.verbose = self.options.verbose #self.show_status_in_summary = self.options.show_status_in_summary self.set_timeout(self.options.timeout) def add_long_output(self, message): """ Appends message to the end of Plugin long_output. Message does not need a \n suffix Examples: >>> p = PluginHelper() >>> p.add_long_output('Status of sensor 1') >>> p.add_long_output('* Temperature: OK') >>> p.add_long_output('* Humidity: OK') >>> p.get_long_output() u'Status of sensor 1\\n* Temperature: OK\\n* Humidity: OK' """ self._long_output.append(message) def add_option(self, *args, **kwargs): """ Same as self.parser.add_option() """ return self.parser.add_option(*args, **kwargs) def get_long_output(self): """ Returns all long_output that has been added via add_long_output """ return '\n'.join(self._long_output) def set_long_output(self, message): """ Overwrite current long_output with message Example: >>> s = PluginHelper() >>> s.add_long_output('first long output') >>> s.set_long_output('Fatal error') >>> s.get_long_output() u'Fatal error' """ self._long_output = [message] def add_summary(self, message): """ Adds message to Plugin Summary """ self._summary.append(message.strip()) def set_summary(self, message): """ Overwrite current summary with message Example: >>> s = PluginHelper() >>> s.add_summary('first summary') >>> s.set_summary('Fatal error') >>> s.get_summary() u'Fatal error' """ self._summary = [message] def get_summary(self): return '. '.join(self._summary) def get_status(self): """ Returns the worst nagios status (integer 0,1,2,3) that has been put with add_status() If status has never been added, returns 3 for UNKNOWN """ # If no status has been set, return unknown if self._nagios_status == -1: return UNKNOWN else: return self._nagios_status def status(self, new_status=None): """ Same as get_status() if new_status=None, otherwise call add_status(new_status) """ if new_status is None: return self.get_status() if new_status not in state_text: new_status = unknown return self.add_status(new_status) def add_status(self, new_status=None): """ Update exit status of the nagios plugin. This function will keep history of the worst status added Examples: >>> p = PluginHelper() >>> p.add_status(0) # ok >>> p.add_status(2) # critical >>> p.add_status(1) # warning >>> p.get_status() # 2 >>> p = PluginHelper() >>> p.add_status('warning') >>> p.add_status('ok') >>> p.get_status() 1 >>> p.add_status('okay') Traceback (most recent call last): ... Exception: Invalid status supplied "okay" """ # If new status was entered as a human readable string (ok,warn,etc) # lets convert it to int: if isinstance(new_status, basestring): if new_status.lower() in state: new_status = state[new_status] else: raise Exception("Invalid status supplied \"%s\"" % (new_status)) self._nagios_status = max(self._nagios_status, new_status) def add_metric(self, label="", value="", warn="", crit="", min="", max="", uom="", perfdatastring=None): """ Add numerical metric (will be outputted as nagios performanca data) Examples: >>> p = PluginHelper() >>> p.add_metric(label="load1", value="7") >>> p.add_metric(label="load5", value="5") >>> p.add_metric(label="load15",value="2") >>> p.get_perfdata() "'load1'=7;;;; 'load5'=5;;;; 'load15'=2;;;;" >>> p = PluginHelper() >>> p.add_metric(perfdatastring="load1=6;;;;") >>> p.add_metric(perfdatastring="load5=4;;;;") >>> p.add_metric(perfdatastring="load15=1;;;;") >>> p.get_perfdata() "'load1'=6;;;; 'load5'=4;;;; 'load15'=1;;;;" """ if not perfdatastring is None: self._perfdata.add_perfdatametric(perfdatastring=perfdatastring) else: self._perfdata.add_perfdatametric(label=label, value=value, warn=warn, crit=crit, min=min, max=max, uom=uom) def get_default_values(self, section_name=None, config_file=None): """ Returns an optionParser.Values instance of all defaults after parsing extra opts config file The Nagios extra-opts spec we use is the same as described here: http://nagiosplugins.org/extra-opts Arguments """ # Get the program defaults values = self.parser.get_default_values() # Create an ExtraOptsParser instance and get all the values from that # config file extra_opts = ExtraOptsParser(section_name=section_name, config_file=config_file).get_values() for option in self.parser.option_list: name = option.dest if name in extra_opts: if option.action == 'append': setattr(values, name, extra_opts[option.dest]) else: setattr(values, name, extra_opts[option.dest][0]) return values def get_metric(self, label): """ Return one specific metric (PerfdataMetric object) with the specified label. Returns None if not found. Example: >>> p = PluginHelper() >>> p.add_metric(label="load1", value="7") >>> p.add_metric(label="load15",value="2") >>> p.get_metric("load1") 'load1'=7;;;; >>> p.get_metric("unknown") # Returns None """ for i in self._perfdata.metrics: if i.label == label: return i return None def convert_perfdata(self, perfdata): """ Converts new threshold range format to old one. Returns None. Examples: x..y -> x:y inf..y -> :y -inf..y -> :y x..inf -> x: -inf..inf -> : """ for metric in perfdata: metric.warn = reconsile_threshold(metric.warn) metric.crit = reconsile_threshold(metric.crit) return None def get_perfdata(self): """ Get perfdatastring for all valid perfdatametrics collected via add_perfdata Examples: >>> p = PluginHelper() >>> p.add_metric(label="load1", value="7", warn="-inf..10", crit="10..inf") >>> p.add_metric(label="load5", value="5", warn="-inf..7", crit="7..inf") >>> p.add_metric(label="load15",value="2", warn="-inf..5", crit="5..inf") >>> p.get_perfdata() "'load1'=7;10:;~:10;; 'load5'=5;7:;~:7;; 'load15'=2;5:;~:5;;" Example with legacy output (show_legacy should be set with a cmdline option): >>> p.show_legacy = True >>> p.get_perfdata() "'load1'=7;10:;~:10;; 'load5'=5;7:;~:7;; 'load15'=2;5:;~:5;;" """ # Normalize the perfdata to so the thresholds match the current nagios plugin guidelines self.convert_perfdata(self._perfdata.metrics) return str(self._perfdata) def get_plugin_output(self, exit_code=None, summary=None, long_output=None, perfdata=None): """ Get all plugin output as it would be printed to screen with self.exit() Examples of functionality: >>> p = PluginHelper() >>> p.get_plugin_output() u'Unknown -' >>> p = PluginHelper() >>> p.add_summary('Testing') >>> p.add_long_output('Long testing output') >>> p.add_long_output('More output') >>> p.get_plugin_output(exit_code=0) u'OK - Testing\\nLong testing output\\nMore output' >>> p = PluginHelper() >>> p.add_summary('Testing') >>> p.add_status(0) >>> p.get_plugin_output() u'OK - Testing' >>> p = PluginHelper() >>> p.show_status_in_summary = False >>> p.add_summary('Testing') >>> p.add_metric(label="load1", value="7") >>> p.add_metric(label="load5", value="5") >>> p.add_metric(label="load15",value="2") >>> p.get_plugin_output(exit_code=0) u"Testing | 'load1'=7;;;; 'load5'=5;;;; 'load15'=2;;;;" >>> p = PluginHelper() >>> p.show_status_in_summary = False >>> p.add_summary('Testing') >>> p.add_long_output('Long testing output') >>> p.add_long_output('More output') >>> p.add_metric(label="load1", value="7") >>> p.add_metric(label="load5", value="5") >>> p.add_metric(label="load15",value="2") >>> p.get_plugin_output(exit_code=0) u"Testing | 'load1'=7;;;; 'load5'=5;;;; 'load15'=2;;;;\\nLong testing output\\nMore output" """ if summary is None: summary = self.get_summary() if long_output is None: long_output = self.get_long_output() if perfdata is None: perfdata = self.get_perfdata() if exit_code is None: exit_code = self.get_status() return_buffer = "" if self.show_status_in_summary is True: return_buffer += "%s - " % state_text[exit_code] if self.show_summary is True: return_buffer += summary if self.show_perfdata is True and len(perfdata) > 0: return_buffer += " | %s\n" % perfdata if not return_buffer.endswith('\n'): return_buffer += '\n' if self.show_longoutput is True and len(long_output) > 0: return_buffer += long_output return_buffer = return_buffer.strip() return return_buffer def set_timeout(self, seconds=50): """ Configures plugin to timeout after seconds number of seconds """ timeout = lambda x, y: self.exit( unknown, summary="Plugin timeout exceeded after %s seconds." % seconds) signal.signal(signal.SIGALRM, timeout) signal.alarm(seconds) def exit(self, exit_code=None, summary=None, long_output=None, perfdata=None): """ Print all collected output to screen and exit nagios style, no arguments are needed except if you want to override default behavior. Arguments: summary -- Is this text as the plugin summary instead of self.get_summary() long_output -- Use this text as long_output instead of self.get_long_output() perfdata -- Use this text instead of self.get_perfdata() exit_code -- Use this exit code instead of self.status() """ if exit_code is None: exit_code = self.get_status() if self.options and self.options.get_metrics is True: summary = "Available metrics for this plugin:" metrics = [] for i in self._perfdata.metrics: if self.options.verbose is True: metrics.append(str(i)) else: metrics.append(i.label) long_output = '\n'.join(metrics) plugin_output = self.get_plugin_output(exit_code=exit_code, summary=summary, long_output=long_output, perfdata=perfdata) print(plugin_output) sys.exit(exit_code) def check_metric(self, metric_name, thresholds): """ Check one specific metric against a list of thresholds. Updates self.status() and writes to summary or longout as appropriate. Arguments: metric_name -- A string representing the name of the metric (the label part of the performance data) thresholds -- a list in the form of [ (level,range) ] where range is a string in the format of "start..end" Examples: >>> p = PluginHelper() >>> thresholds = [(warning,'2..5'), (critical,'5..inf')] >>> p.get_plugin_output() u'Unknown -' >>> p.add_metric('load15', '3') >>> p.check_metric('load15',thresholds) >>> p.get_plugin_output() u"Warning - Warning on load15 | 'load15'=3;@2:5;~:5;;" >>> p = PluginHelper() >>> thresholds = [(warning,'2..5'), (critical,'5..inf')] >>> p.add_metric('load15', '3') >>> p.verbose = True >>> p.check_metric('load15',thresholds) >>> p.get_plugin_output() u"Warning - Warning on load15 | 'load15'=3;@2:5;~:5;;\\nWarning on load15" Invalid metric: >>> p = PluginHelper() >>> p.add_status(ok) >>> p.add_summary('Everythings fine!') >>> p.get_plugin_output() u'OK - Everythings fine!' >>> thresholds = [(warning,'2..5'), (critical,'5..inf')] >>> p.check_metric('never_added_metric', thresholds) >>> p.get_plugin_output() u'Unknown - Everythings fine!. Metric never_added_metric not found' Invalid threshold: >>> p = PluginHelper() >>> thresholds = [(warning, 'invalid'), (critical,'5..inf')] >>> p.add_metric('load1', '10') >>> p.check_metric('load1', thresholds) Traceback (most recent call last): ... SystemExit: 3 Returns: None """ metric = self.get_metric(label=metric_name) # If threshold was specified but metric not found in our data, set # status unknown if metric is None: self.status(unknown) self.add_summary("Metric %s not found" % (metric_name)) return metric_status = -1 # by default assume nothing default_state = 0 # By default if no treshold matches, we assume OK highest_level = ok # highest threshold range seen # Iterate through all thresholds, and log down warn and crit for # perfdata purposes for level, threshold_range in thresholds: if metric.warn == '' and level == warning: metric.warn = threshold_range elif metric.crit == '' and level == critical: metric.crit = threshold_range if level == ok: default_state = 2 # Iterate all threshold and determine states for level, threshold_range in thresholds: highest_level = max(highest_level, level) # If ok threshold was specified, default state is critical according to spec # If value matches our threshold, we increment the status try: in_range = new_threshold_syntax.check_range( metric.value, threshold_range) except pynag.errors.PynagError: self.set_summary( "Could not parse threshold %s=%s for metric %s" % (state_text[level], threshold_range, metric_name)) self.set_long_output( "Thresholds should be in the format metric=<metric_name>,ok=0..90,warning=90..95" ) self.add_long_output("Example: ") self.add_long_output( "--th metric=load,ok=0..1,warning=1..5,critical=5..inf") self.status(unknown) self.exit() if in_range: metric_status = max(metric_status, level) self.debug('%s is within %s range "%s"' % (metric_name, state_text[level], threshold_range)) if level == ok: self.debug( "OK threshold matches, not checking any more thresholds" ) metric_status = ok break else: self.debug('%s is outside %s range "%s"' % (metric_name, state_text[level], threshold_range)) # If no thresholds matched, set a default return code if metric_status < 0: metric_status = default_state # OK's go to long output, errors go directly to summary self.add_status(metric_status) message = '%s on %s' % (state_text[metric_status], metric_name) # Errors are added to the summary: if metric_status > 0: self.add_summary(message) if self.verbose is True: self.add_long_output(message) def check_all_metrics(self): """ Checks all metrics (add_metric() against any thresholds set in self.options.thresholds or with --threshold from commandline)""" checked_metrics = [] for threshold in self.thresholds: parsed_threshold = new_threshold_syntax.parse_threshold(threshold) metric_name = parsed_threshold['metric'] thresholds = parsed_threshold['thresholds'] self.check_metric(metric_name, thresholds) checked_metrics.append(metric_name) # Lets look at metrics that were not specified on the command-line but might have a default # threshold specified with their metric data for i in self._perfdata.metrics: if i.label in checked_metrics: continue thresholds = [] if i.warn != '': thresholds.append((warning, i.warn)) if i.crit != '': thresholds.append((critical, i.crit)) self.check_metric(i.label, thresholds) def run_function(self, function, *args, **kwargs): """ Executes "function" and exits Nagios style with status "unkown" if there are any exceptions. The stacktrace will be in long_output. Example: >>> p = PluginHelper() >>> p.add_status('ok') >>> p.get_status() 0 >>> p.add_status('okay') Traceback (most recent call last): ... Exception: Invalid status supplied "okay" >>> p.run_function( p.add_status, 'warning' ) >>> p.get_status() 1 >>> p.run_function( p.add_status, 'okay' ) Traceback (most recent call last): ... SystemExit: 3 """ try: function(*args, **kwargs) except Exception: exc_type, exc_value, exc_traceback = sys.exc_info() exit_code = unknown # traceback.print_exc(file=sys.stdout) summary = "Unhandled '%s' exception while running plugin (traceback below)" % exc_type long_output = traceback.format_exc() self.exit(exit_code=exit_code, summary=summary, long_output=long_output, perfdata='') def debug(self, message): # pragma: no cover if self.show_debug is True: self.add_long_output("debug: %s" % message) def __str__(self): """ >>> p = PluginHelper() >>> p.add_status(ok) >>> p.add_summary('Test') >>> print(p) OK - Test """ return self.get_plugin_output() def __repr__(self): return self.get_plugin_output(long_output='', perfdata='')
def __init__(self): self._long_output = [] self._summary = [] self.thresholds = [] # Performance and Threshold Metrics are stored here self._perfdata = PerfData() self.parser = OptionParser() generic_group = OptionGroup(self.parser, "Generic Options") generic_group.add_option( '--timeout', help="Exit plugin with unknown status after x seconds", type='int', metavar='50', dest="timeout", default=self.timeout ) generic_group.add_option( '--threshold', default=[], help="Thresholds in standard nagios threshold format", metavar='range', dest="thresholds", action="append" ) generic_group.add_option( '--th', default=[], help="Same as --threshold", metavar='range', dest="thresholds", action="append" ) generic_group.add_option( '--extra-opts', help="Read options from an ini file. See http://nagiosplugins.org/extra-opts", metavar='@file', dest="extra_opts" ) generic_group.add_option( "-d", "--debug", dest="show_debug", help="Print debug info", metavar="d", action="store_true", default=self.show_debug ) # Display options are options that affect the output of the plugin # But usually not its function display_group = OptionGroup(self.parser, "Display Options") display_group.add_option( "-v", "--verbose", dest="verbose", help="Print more verbose info", metavar="v", action="store_true", default=self.verbose ) display_group.add_option( "--no-perfdata", dest="show_perfdata", help="Dont show any performance data", action="store_false", default=self.show_perfdata ) display_group.add_option( "--no-longoutput", dest="show_longoutput", help="Hide longoutput from the plugin output (i.e. only display first line of the output)", action="store_false", default=self.show_longoutput ) display_group.add_option( "--no-summary", dest="show_summary", help="Hide summary from plugin output", action="store_false", default=self.show_summary ) display_group.add_option( "--get-metrics", dest="get_metrics", help="Print all available metrics and exit (can be combined with --verbose)", action="store_true", default=False ) display_group.add_option( "--legacy", dest="show_legacy", help="Deprecated, do not use", action="store_true", default=self.show_legacy ) self.parser.add_option_group(generic_group) self.parser.add_option_group(display_group)
def __init__(self): self._long_output = [] self._summary = [] self.thresholds = [] self._perfdata = PerfData( ) # Performance and Threshold Metrics are stored here self.parser = OptionParser() general = OptionGroup(self.parser, "Generic Options") self.parser.add_option( '--threshold', '--th', default=[], help="Thresholds in standard nagios threshold format", metavar='', dest="thresholds", action="append") display_group = OptionGroup(self.parser, "Display Options") display_group.add_option("-v", "--verbose", dest="verbose", help="Print more verbose info", metavar="v", action="store_true", default=self.verbose) general.add_option("-d", "--debug", dest="show_debug", help="Print debug info", metavar="d", action="store_true", default=self.show_debug) display_group.add_option("--no-perfdata", dest="show_perfdata", help="Dont show any performance data", action="store_false", default=self.show_perfdata) display_group.add_option( "--no-longoutput", dest="show_longoutput", help= "Hide longoutput from the plugin output (i.e. only display first line of the output)", action="store_false", default=self.show_longoutput) display_group.add_option("--no-summary", dest="show_summary", help="Hide summary from plugin output", action="store_false", default=self.show_summary) #display_group.add_option("--show-status-in-summary", dest="show_status_in_summary", help="Prefix the summary of the plugin with OK- or WARN- ", action="store_true", default=False) display_group.add_option( "--get-metrics", dest="get_metrics", help= "Print all available metrics and exit (can be combined with --verbose)", action="store_true", default=False) display_group.add_option("--legacy", dest="show_legacy", help="Output perfdata in legacy format", action="store_true", default=self.show_legacy) self.parser.add_option_group(display_group)