Example #1
0
    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)
Example #2
0
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)
Example #3
0
    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)
Example #4
0
 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, ))
Example #5
0
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
Example #6
0
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
Example #7
0
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)
Example #8
0
    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))
Example #9
0
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
Example #10
0
 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)
Example #11
0
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
Example #12
0
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
Example #13
0
    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")
Example #14
0
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