def resolve_macro(self, macroname, default='raise exception'): """ Returns the resolved value of a given macro. Arguments: macroname - the name of the macro, e.g. num_problems default - If given, return this when macroname is not found If default is not specified, exception will be raised if macro could not be resolved """ state_summary = self.get_state_summary() if macroname not in self.get_all_macros(): if default == 'raise exception': raise PynagError(_("Could not resolve macro '%s'") % macroname) else: return default elif macroname == 'num_state_0': return state_summary[0] elif macroname == 'num_state_1': return state_summary[1] elif macroname == 'num_state_2': return state_summary[2] elif macroname == 'num_state_3': return state_summary[3] elif macroname == 'num_problems': return sum(state_summary[1:]) elif macroname == 'num_problems': return sum(state_summary[1:]) elif macroname == 'percent_state_0': if len(self.get_all_states()) == 0: return 0 return 100.0 * state_summary[0] / sum(state_summary) elif macroname == 'percent_state_1': if len(self.get_all_states()) == 0: return 0 return 100.0 * state_summary[1] / sum(state_summary) elif macroname == 'percent_state_2': if len(self.get_all_states()) == 0: return 0 return 100.0 * state_summary[2] / sum(state_summary) elif macroname == 'percent_state_3': if len(self.get_all_states()) == 0: return 0 return 100.0 * state_summary[3] / sum(state_summary) elif macroname == 'percent_problems': if len(self.get_all_states()) == 0: return 0 return 100.0 * sum(state_summary[1:]) / sum(state_summary) elif macroname == 'current_state': return self.get_status() elif macroname == 'friendly_state': return self.get_human_friendly_status(resolve_macros=False) else: raise PynagError( _("Dont know how to resolve macro named '%s'") % macroname)
class Host(BusinessProcess): status_calculation_methods = ['worst_service_state', 'host_state'] _default_status_calculation_method = 'worst_service_state' process_type = 'host' def load(self): self._livestatus = adagios.status.utils.livestatus(request=None) self._host = self._livestatus.get_host(self.name, backend=None) self.display_name = self._host.get('display_name') or self.name self.notes = self._host.get( 'notes') or 'You are looking at the host %s' % self.name def get_status(self): try: self.load() except Exception, e: self.errors.append(e) return 3 method = self.status_method if method == 'worst_service_state': return self._host.get('worst_service_state', 3) elif method == 'host_state': return self._host.get('state', 3) else: raise PynagError( _("%s is not a status calculation method i know") % method)
def save(self): """ Save this businessprocess to a file """ json_data = get_all_json() # If we are renaming a process, take special # Precautions that we are not overwriting a current one if self.name != self._original_name and self.name in get_all_process_names( ): raise PynagError( _("Cannot rename process to %s. Another process with same name already exists" ) % (self.name)) # Look for a json object that matches our name for i, data in enumerate(json_data): current_name = data.get('name', None) if not current_name: continue # We found our item, lets save it if current_name == self._original_name: json_data[i] = self.data break else: # If we get here, object was not found, so lets assume # We are saving a new one json_data.append(self.data) # Once we get here, all we need to do is save our item json_string = json.dumps(json_data, indent=4) self._write_file(json_string)
def wrap(filename, *args, **kwargs): if filename.startswith(self.tempdir): return func(filename, *args, **kwargs) else: raise PynagError( "FakeNagiosEnvironment tried to open file outside its sandbox: %s" % (filename, ))
def find_command_file(cfg_file=None): """ Returns path to nagios command_file by looking at what is defined in nagios.cfg Args: cfg_file (str): Path to nagios.cfg configuration file Returns: str. Path to the nagios command file Raises: PynagError """ global path_to_command_file # If we have been called before, the path should be cached in a global variable if path_to_command_file: return path_to_command_file # If we reach here, we have to parse nagios.cfg to find path # to our command file c = config(cfg_file=cfg_file) command_file = c.get_cfg_value('command_file') if not command_file: raise PynagError("command_file not found in your nagios.cfg (%s)" % c.cfg_file) path_to_command_file = command_file return command_file
def check_range(value, range): """ Returns True if value is within range, else False Arguments: value -- Numerical value to check, can be any number range -- string in the format of "start..end" Examples: >>> check_range(5, "0..10") True >>> check_range(11, "0..10") False """ if not isinstance(range, basestring) or range == '': raise PynagError('range must be a string') # value must be numeric, so we try to convert it to float value = float(value) # If range does not contain ".." then we assume its the older style of # ranges (either a plain number or the start:end syntax) if '..' not in range: return not pynag.Plugins.check_range(value=value, range_threshold=range) # If range starts with ^ we the conditions are inverted if range[0] == '^': return not check_range(value, range[1:]) # Start and end must be defined tmp = range.split('..') if len(tmp) != 2: raise PynagError('Invalid Format for threshold range: "%s"' % range) start, end = tmp if not start in ('inf', '-inf'): start = float(start) if start > value: return False if not end == 'inf': end = float(end) if end < value: return False return True
def find_pnp_path(): """ Look through common locations of pnp4nagios, tries to locate it automatically """ possible_paths = [settings.pnp_filepath] possible_paths += [ "/usr/share/pnp4nagios/html/index.php", "/usr/share/nagios/html/pnp4nagios/index.php" ] for i in possible_paths: if os.path.isfile(i): return i raise PynagError("Could not find pnp4nagios/index.php. Please specify it in adagios->settings->PNP. Tried %s" % possible_paths)
def resolve_macrostring(self, string): """ Resolve all macros in a given string, and return the resolved string >>> bp = get_business_process('test business process') >>> bp.resolve_macrostring("number of problems: {num_problems}") 'number of problems: 0' For a list of supported macros, call self.resolve_all_macros() """ all_macros = self.resolve_all_macros() try: return string.format(**all_macros) except KeyError, e: raise PynagError("Invalid macro in string. %s" % str(e))
def find_command_file(cfg_file=None): """ Returns path to nagios command_file by looking at what is defined in nagios.cfg """ c = config(cfg_file=cfg_file) c.parse() command_file = None for k, v in c.maincfg_values: if k == 'command_file': command_file = v break if not command_file: if not command_file: raise PynagError("command_file not found in your nagios.cfg (%s)" % c.cfg_file) return command_file
def get_status(self): try: self.load() except Exception as e: self.errors.append(e) return 3 method = self.status_method if method == 'worst_service_state': return self._host.get('worst_service_state', 3) elif method == 'host_state': return self._host.get('state', 3) else: raise PynagError( _("%s is not a status calculation method i know") % method)
def check_range(value, range): """ Returns True if value is within range, else False Arguments: value -- Numerical value to check, can be any number range -- string in the format of "start..end" Examples: >>> check_range(5, "0..10") True >>> check_range(11, "0..10") False """ if not type(range) == type('') or range == '': raise PynagError('range must be a string') # value must be numeric, so we try to convert it to float value = float(value) # If range starts with ^ we the conditions are inverted if range[0] == '^': return not check_range(value, range[1:]) # Start and end must be defined tmp = range.split('..') if len(tmp) != 2: raise PynagError('Invalid Format for threshold range: "%s"' % range) start, end = tmp if not start in ('inf','-inf'): start = float(start) if start > value: return False if not end == 'inf': end = float(end) if end < value: return False return True
def parse_threshold(threshold): """ takes a threshold string as an input and returns a hash map of options and values Examples: >>> parse_threshold('metric=disk_usage,ok=0..90,warning=90..95,critical=95.100') {'thresholds': [(0, '0..90'), (1, '90..95'), (2, '95.100')], 'metric': 'disk_usage'} """ tmp = threshold.lower().split(',') parsed_thresholds = [] results = {} results['thresholds'] = parsed_thresholds for i in tmp: if i.find('=') < 1: raise PynagError( "Invalid input: '%s' is not of the format key=value" % i) key, value = i.split('=', 1) if key in pynag.Plugins.state.keys(): parsed_thresholds.append((pynag.Plugins.state[key], value)) else: results[key] = value return results
def _guess_method(self): """ Guesses whether to run via SYSV INIT script og via systemd. Will also modify nagios_init="service nagios" and set service_name=nagios and method to SYSV_INIT_SCRIPT :returns: ``deamon.SYSTEMD`` :rtype: int """ if self.nagios_init and os.path.exists(self.nagios_init): return daemon.SYSV_INIT_SCRIPT elif self.nagios_init and self.nagios_init.split( None, 1)[0].endswith("service"): self.service_name = self.nagios_init.split(None, 1)[1] return daemon.SYSV_INIT_SERVICE elif os.path.exists("%s/%s.service" % (daemon.systemd_service_path, self.service_name)): return daemon.SYSTEMD else: raise PynagError("Unable to detect daemon method, " "could not find init script or " "systemd unit file")
def check_range(value, range_threshold=None): """ Returns True if value is within range_threshold. Format of range_threshold is according to: http://nagiosplug.sourceforge.net/developer-guidelines.html#THRESHOLDFORMAT Arguments: value -- Numerical value to check (i.e. 70 ) range -- Range to compare against (i.e. 0:90 ) Returns: True -- If value is inside the range False -- If value is outside the range (alert if this happens) False -- if invalid value is specified Summary from plugin developer guidelines: --------------------------------------------------------- x Generate an alert if x... --------------------------------------------------------- 10 < 0 or > 10, (outside the range of {0 .. 10}) 10: < 10, (outside {10 .. ∞}) ~:10 > 10, (outside the range of {-∞ .. 10}) 10:20 < 10 or > 20, (outside the range of {10 .. 20}) @10:20 ≥ 10 and ≤ 20, (inside the range of {10 .. 20}) 10 < 0 or > 10, (outside the range of {0 .. 10}) --------------------------------------------------------- # Example runs for doctest, False should mean alert >>> check_range(78, "90") # Example disk is 78% full, threshold is 90 True >>> check_range(5, 10) # Everything between 0 and 10 is True True >>> check_range(0, 10) # Everything between 0 and 10 is True True >>> check_range(10, 10) # Everything between 0 and 10 is True True >>> check_range(11, 10) # Everything between 0 and 10 is True False >>> check_range(-1, 10) # Everything between 0 and 10 is True False >>> check_range(-1, "~:10") # Everything Below 10 True >>> check_range(11, "10:") # Everything above 10 is True True >>> check_range(1, "10:") # Everything above 10 is True False >>> check_range(0, "5:10") # Everything between 5 and 10 is True False >>> check_range(0, "@5:10") # Everything outside 5:10 is True True >>> check_range(None) # Return False if value is not a number False >>> check_range("10000000 PX") # What happens on invalid input False >>> check_range("10000000", "invalid:invalid") # What happens on invalid range Traceback (most recent call last): ... PynagError: Invalid threshold format: invalid:invalid """ # Return false if value is not a number try: float(value) except Exception: return False # if no range_threshold is provided, assume everything is ok if not range_threshold: range_threshold = '~:' range_threshold = str(range_threshold) # If range starts with @, then we do the opposite if range_threshold[0] == '@': return not check_range(value, range_threshold[1:]) if range_threshold.find(':') > -1: (start, end) = (range_threshold.split(':', 1)) # we get here if ":" was not provided in range_threshold else: start = '' end = range_threshold # assume infinity if start is not provided if start == '~': start = None # assume start=0 if start is not provided if start == '': start = 0 # assume infinity if end is not provided if end == '': end = None try: # start is defined and value is lower than start if start is not None and float(value) < float(start): return False if end is not None and float(value) > float(end): return False except ValueError: raise PynagError("Invalid threshold format: %s" % range_threshold) return True