Ejemplo n.º 1
0
    def test_expected_02(self):

        expected_results = {
            -1: nagios.state.warning,
            4: nagios.state.warning,
            4.99999: nagios.state.warning,
            5: nagios.state.ok,
            14.21: nagios.state.ok,
            33: nagios.state.ok,
            33.00001: nagios.state.warning,
            102321: nagios.state.warning,
        }

        log.info("Testing NagiosThreshold object with warning range 5:33.")
        try:

            t = NagiosThreshold(warning = "5:33", critical = '')
            log.debug("NagiosThreshold object: %r", t)

            for value in sorted(expected_results.keys()):
                exp_result = expected_results[value]
                result = t.get_status(value)
                log.debug("Check %r, result is %r, expected is %r", value,
                        result, exp_result)
                if not exp_result == result:
                    self.fail("Unexpected result of get_status(), checked %r, "
                            "got %r, expected %r." % (value,
                            result, exp_result))

        except Exception as e:
            self.fail("Could not instatiate NagiosThreshold by a %s: %s" % (
                    e.__class__.__name__, str(e)))
Ejemplo n.º 2
0
    def set_thresholds(self, warning=None, critical=None):
        """
        Initialisation of self.threshold as a the NagiosThreshold object.

        @param warning: the warning threshold
        @type warning: str, int, long, float or NagiosRange
        @param critical: the critical threshold
        @type critical: str, int, long, float or NagiosRange

        @return: the generated threshold object
        @rtype: NagiosThreshold

        """

        self.threshold = NagiosThreshold(
            warning=warning, critical=critical)

        return self.threshold
Ejemplo n.º 3
0
    def test_expected_03(self):

        expected_results = {
            -1: nagios.state.ok,
            4: nagios.state.ok,
            29.99999: nagios.state.ok,
            30: nagios.state.ok,
            30.00001: nagios.state.warning,
            59.99999: nagios.state.warning,
            60: nagios.state.warning,
            60.00001: nagios.state.critical,
            102321: nagios.state.critical,
        }

        log.info("Testing NagiosThreshold object with warning range ~:30 " +
                "and critical range ~:60.")
        try:

            t = NagiosThreshold(warning = "~:30", critical = '~:60')
            log.debug("NagiosThreshold object: %r", t)
            if not t.critical.is_set:
                self.fail("Critical threshold must be set.")
            if not t.warning.is_set:
                self.fail("Warning threshold must be set.")
            if t.critical.start is not None:
                self.fail("Critical range start must be None.")
            self.assertEqual(t.critical.end, 60, "Critical range end must be 60.")
            if t.warning.start is not None:
                self.fail("Warning range start must be None.")
            self.assertEqual(t.warning.end, 30, "Warning range end must be 30.")

            for value in sorted(expected_results.keys()):
                exp_result = expected_results[value]
                result = t.get_status(value)
                log.debug("Check %r, result is %r, expected is %r", value,
                        result, exp_result)
                if not exp_result == result:
                    self.fail("Unexpected result of get_status(), checked %r, "
                            "got %r, expected %r." % (value,
                            result, exp_result))

        except Exception as e:
            self.fail("Could not instatiate NagiosThreshold by a %s: %s" % (
                    e.__class__.__name__, str(e)))
Ejemplo n.º 4
0
    def test_threshold_empty(self):

        log.info("Testing NagiosThreshold object with two empty strings.")
        try:
            t = NagiosThreshold(warning = '', critical = '')
            log.debug("NagiosThreshold object: %r", t)
            if t.warning.is_set:
                self.fail("Warning threshold may not be set.")
            log.debug("Warning threshold is not set.")
            if t.critical.is_set:
                self.fail("Critical threshold may not be set.")
            log.debug("Critical threshold is not set.")
        except Exception as e:
            self.fail("Could not instatiate NagiosThreshold by a %s: %s" % (
                    e.__class__.__name__, str(e)))
Ejemplo n.º 5
0
    def test_threshold_critical_80(self):

        log.info("Testing NagiosThreshold object with critical == 80.")
        try:
            t = NagiosThreshold(warning = '', critical = '80')
            log.debug("NagiosThreshold object: %r", t)
            if t.warning.is_set:
                self.fail("Warning threshold may not be set.")
            log.debug("Warning threshold is not set.")
            if not t.critical.is_set:
                self.fail("Critical threshold must be set.")
            if not t.critical.start == 0:
                self.fail("Critical threshold range start must be zero.")
            if not t.critical.end == 80:
                self.fail("Critical threshold range end must be 80.")
        except Exception as e:
            self.fail("Could not instatiate NagiosThreshold by a %s: %s" % (
                    e.__class__.__name__, str(e)))
Ejemplo n.º 6
0
 def test_performance_object_00(self):
     log.info("Testing init NagiosPerformance object lap 0.")
     warn_range = NagiosRange('30')
     crit_range = NagiosRange('60')
     th = NagiosThreshold(warning = warn_range, critical = crit_range)
     perf = NagiosPerformance(label = 'bla', value = 10, threshold = th,
             uom = 'MByte', min_data = 0, max_data = 1000)
     log.debug("NagiosPerformance object: %r", perf)
     self.assertEqual(perf.label, 'bla', 'Error testing perf.label')
     self.assertEqual(perf.value, 10, 'Error testing perf.value')
     self.assertEqual(perf.uom, 'MByte', 'Error testing perf.uom')
     self.assertEqual(perf.warning.start, 0, 'Error testing perf.warning.start')
     self.assertEqual(perf.warning.end, 30, 'Error testing perf.warning.end')
     self.assertEqual(perf.critical.start, 0, 'Error testing perf.critical.start')
     self.assertEqual(perf.critical.end, 60, 'Error testing perf.critical.end')
     self.assertEqual(perf.min_data, 0, 'Error testing perf.min_data')
     self.assertEqual(perf.max_data, 1000, 'Error testing perf.max_data')
     self.assertEqual(perf.status(), nagios.state.ok, 'Error testing perf.status()')
Ejemplo n.º 7
0
    def __call__(self):
        """
        Method to call the plugin directly.
        """

        self.parse_args()
        self.init_root_logger()

        if self.argparser.args.delay < 0.2:
            msg = "The delay must be in minimum 0.2 seconds."
            self.die(msg)
        self.delay = self.argparser.args.delay

        if self.argparser.args.iterations < 1:
            msg = "There must be in minimum one iteration."
            self.die(msg)
        self.iterations = self.argparser.args.iterations

        msg_tpl = ("The %s thresholds must be given in the form "
                   "'IO_DELAY_90,IO_DELAY_50,IO_DELAY_10', where the "
                   "values are integer values.")
        re_limits = re.compile(r'^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*$')

        match = re_limits.search(self.argparser.args.warning)
        if not match:
            self.die(msg_tpl % ('warning'))
        self.warning = (int(match.group(1)), int(match.group(2)),
                        int(match.group(3)))

        match = re_limits.search(self.argparser.args.critical)
        if not match:
            self.die(msg_tpl % ('critical'))
        self.critical = (int(match.group(1)), int(match.group(2)),
                         int(match.group(3)))

        if self.verbose > 1:
            log.debug("Got thresholds: warning: %r, critical: %r.",
                      self.warning, self.critical)
            log.debug("Number of iterations: %d, delay between: %.1f seconds.",
                      self.iterations, self.delay)
            log.debug("Initialisation complete.")

        if os.geteuid():
            self.die("This plugin must be executed as root.")

        self.get_proc_stats()
        self.evaluate_proc_stats()

        state = nagios.state.ok

        if (self.process_count['90'] >= self.critical[0]
                or self.process_count['50'] >= self.critical[1]
                or self.process_count['10'] >= self.critical[2]):
            state = nagios.state.critical
        elif (self.process_count['90'] >= self.warning[0]
              or self.process_count['50'] >= self.warning[1]
              or self.process_count['10'] >= self.warning[2]):
            state = nagios.state.warning

        t_90 = NagiosThreshold(
            warning=":%d" % (self.warning[0]),
            critical=":%d" % (self.critical[0]),
        )

        t_50 = NagiosThreshold(
            warning=":%d" % (self.warning[1]),
            critical=":%d" % (self.critical[1]),
        )

        t_10 = NagiosThreshold(
            warning=":%d" % (self.warning[2]),
            critical=":%d" % (self.critical[2]),
        )

        self.add_perfdata(
            label='total_procs',
            value=self.process_count['total'],
        )

        self.add_perfdata(label='iodelay_90',
                          value=self.process_count['90'],
                          threshold=t_90)

        self.add_perfdata(label='iodelay_50',
                          value=self.process_count['50'],
                          threshold=t_50)

        self.add_perfdata(label='iodelay_10',
                          value=self.process_count['10'],
                          threshold=t_10)

        msg = ("Total %(total)d procs, %(90)d procs with i/o delay >= 90%%, "
               "%(50)d procs with i/o delay >= 50%% and %(10)d procs with "
               "i/o delay >= 10%%.")
        out = msg % self.process_count

        self.exit(state, out)
Ejemplo n.º 8
0
    def __call__(self):
        """
        Method to call the plugin directly.
        """

        self.parse_args()
        self.init_root_logger()

        if not self.argparser.args.vg:
            self.die("No volume group to check given.")
        self._vg = self.argparser.args.vg

        if self.verbose > 2:
            log.debug("Current object:\n%s", pp(self.as_dict()))

        # ----------------------------------------------------------
        # Parameters for check_free
        crit = 0
        crit_is_abs = True
        warn = 0
        warn_is_abs = True

        if not self.check_state:

            match_pc = re_number_percent.search(self.argparser.args.critical)
            match_abs = re_number_abs.search(self.argparser.args.critical)

            if match_pc:
                crit = int(match_pc.group(1))
                crit_is_abs = False
            elif match_abs:
                crit = int(match_abs.group(1))
            else:
                self.die("Invalid critical value %r." % (self.argparser.args.critical))
                return

            match_pc = re_number_percent.search(self.argparser.args.warning)
            match_abs = re_number_abs.search(self.argparser.args.warning)

            if match_pc:
                warn = int(match_pc.group(1))
                warn_is_abs = False
            elif match_abs:
                warn = int(match_abs.group(1))
            else:
                self.die("Invalid warning value %r." % (self.argparser.args.warning))
                return

        # ----------------------------------------------------------
        # Getting current state of VG
        vg_state = LvmVgState(
            plugin=self, vg=self.vg, vgs_cmd=self.vgs_cmd,
            verbose=self.verbose, timeout=self.argparser.args.timeout)

        try:
            vg_state.get_data()
        except (ExecutionTimeoutError, VgNotExistsError) as e:
            self.die(str(e))
        except CalledProcessError as e:
            msg = "The %r command returned %d with the message: %s" % (
                self.vgs_cmd, e.returncode, e.output)
            self.die(msg)

        if self.verbose > 1:
            log.debug(
                "Got a state of the volume group %r:\n%s", self.vg, vg_state)

        # ----------------------------------------------
        if self.check_state:

            self.add_message(
                nagios.state.ok, ("Volume group %r seems to be OK." % (self.vg)))

            if 'r' in vg_state.attr:
                self.add_message(
                    nagios.state.warning,
                    ("Volume group %r is in a read-only state." % (self.vg)))

            if 'z' not in vg_state.attr:
                self.add_message(
                    nagios.state.warning, ("Volume group %r is not resizeable." % (self.vg)))

            if 'p' in vg_state.attr:
                self.add_message(
                    nagios.state.critical,
                    (("One or more physical volumes belonging to the "
                        "volume group %r are missing from the system.") % (self.vg)))

            if self.verbose:
                self.out(
                    "Attributes of VG %r: %s" % (self.vg, vg_state.attr_str))

            (state, msg) = self.check_messages()
            self.exit(state, msg)

            # Only for the blinds:
            return

        # ----------------------------------------------
        # And now check free space (or whatever)

        if not vg_state.size_mb:
            self.die(
                "Cannot detect absolute size of volume group %r." % (self.vg))

        c_free_abs = 0
        c_free_pc = 0
        c_used_abs = 0
        c_used_pc = 0
        if crit_is_abs:
            c_free_abs = crit
            c_used_abs = vg_state.size_mb - crit
            c_free_pc = float(crit) / float(vg_state.size_mb) * 100
            c_used_pc = float(c_used_abs) / float(vg_state.size_mb) * 100
        else:
            c_free_pc = float(crit)
            c_used_pc = 100.0 - c_free_pc
            c_free_abs = int(math.ceil(c_free_pc * float(vg_state.size_mb) / 100))
            c_used_abs = vg_state.size_mb - c_free_abs

        w_free_abs = 0
        w_free_pc = 0
        w_used_abs = 0
        w_used_pc = 0
        if warn_is_abs:
            w_free_abs = warn
            w_used_abs = vg_state.size_mb - warn
            w_free_pc = float(warn) / float(vg_state.size_mb) * 100
            w_used_pc = float(w_used_abs) / float(vg_state.size_mb) * 100
        else:
            w_free_pc = float(warn)
            w_used_pc = 100.0 - w_free_pc
            w_free_abs = int(math.ceil(w_free_pc * float(vg_state.size_mb) / 100))
            w_used_abs = vg_state.size_mb - w_free_abs

        if c_free_abs > w_free_abs:
            self.die(
                "The warning threshold must be greater than the critical threshold.")

        th_free_abs = NagiosThreshold(
            warning="@%d" % (w_free_abs), critical="@%d" % (c_free_abs))
        th_used_abs = NagiosThreshold(
            warning="%d" % (w_used_abs), critical="%d" % (c_used_abs))
        th_free_pc = NagiosThreshold(
            warning="@%d" % (w_free_pc), critical="@%d" % (c_free_pc))
        th_used_pc = NagiosThreshold(
            warning="%f" % (w_used_pc), critical="%f" % (c_used_pc))

        if self.verbose:
            self.out(
                "VG %r total size: %8d MiBytes." % (self.vg, vg_state.size_mb))
            self.out(
                "VG %r used size:  %8d MiBytes (%0.2f%%)." % (
                    self.vg, vg_state.used_mb, vg_state.percent_used))
            self.out(
                "VG %r free size:  %8d MiBytes (%0.2f%%)." % (
                    self.vg, vg_state.free_mb, vg_state.percent_free))

        if self.verbose > 2:
            log.debug("Thresholds free MBytes:\n%s", pp(th_free_abs.as_dict()))
            log.debug("Thresholds free percent:\n%s", pp(th_free_pc.as_dict()))
            log.debug("Thresholds used MBytes:\n%s", pp(th_used_abs.as_dict()))
            log.debug("Thresholds used percent:\n%s", pp(th_used_pc.as_dict()))

        self.add_perfdata(
            label='total_size', value=vg_state.size_mb, uom='MB')
        self.add_perfdata(
            label='free_size', value=vg_state.free_mb, uom='MB', threshold=th_free_abs)
        self.add_perfdata(
            label='free_percent', value=float("%0.2f" % (vg_state.percent_free)),
            uom='%', threshold=th_free_pc)
        self.add_perfdata(
            label='alloc_size', value=vg_state.used_mb, uom='MB',
            threshold=th_used_abs)
        self.add_perfdata(
            label='alloc_percent', value=float("%0.2f" % (vg_state.percent_used)),
            uom='%', threshold=th_used_pc)

        state = th_free_abs.get_status(vg_state.free_mb)

        out = "%d MiB total, %d MiB free (%0.1f%%), %d MiB allocated (%0.1f%%)" % (
            vg_state.size_mb, vg_state.free_mb, vg_state.percent_free,
            vg_state.used_mb, vg_state.percent_used)

        self.exit(state, out)
Ejemplo n.º 9
0
class NagiosPlugin(object):
    """
    A encapsulating class for a Nagios plugin.
    """

    pass

    # -------------------------------------------------------------------------
    def __init__(
        self, usage=None, shortname=None, version=nagios.__version__, url=None,
            blurb=None, licence=lgpl3_licence_text, extra=None, plugin=None,
            timeout=default_timeout):
        """
        Constructor of the NagiosPlugin class.

        Instantiate object::

            from nagios.plugin import NagiosPlugin

            # Minimum arguments:
            na = NagiosPlugin(
                usage = 'Usage: %(prog)s --hello',
                version = '0.0.1',
            )

        @param usage: Short usage message used with --usage/-? and with missing
                      required arguments, and included in the longer --help
                      output. Can include %(prog)s placeholder which will be
                      replaced with the plugin name, e.g.::

                          usage = 'Usage: %(prog)s -H <hostname> -p <ports> [-v]'

        @type usage: str
        @param shortname: the shortname of the plugin
        @type shortname: str
        @param version: Plugin version number, included in the --version/-V
                        output, and in the longer --help output. e.g.::

                            $ ./check_tcp_range --version
                            check_tcp_range 0.2 [http://www.openfusion.com.au/labs/nagios/]
        @type version: str
        @param url: URL for info about this plugin, included in the
                    --version/-V output, and in the longer --help output.
                    Maybe omitted.
        @type url: str or None
        @param blurb: Short plugin description, included in the longer
                      --help output. Maybe omitted.
        @type blurb: str or None
        @param licence: License text, included in the longer --help output. By
                        default, this is set to the standard nagios plugins
                        LGPLv3 licence text.
        @type licence: str or None
        @param extra: Extra text to be appended at the end of the longer --help
                      output, maybe omitted.
        @type extra: str or None
        @param plugin: Plugin name. This defaults to the basename of your plugin.
        @type plugin: str or None
        @param timeout: Timeout period in seconds, overriding the standard
                        timeout default (15 seconds).
        @type timeout: int

        """

        self._shortname = shortname
        if self._shortname:
            self._shortname = self._shortname.strip()
        if not self._shortname:
            self._shortname = get_shortname(plugin=plugin)

        self.argparser = None
        if usage:
            self.argparser = NagiosPluginArgparse(
                usage=usage,
                version=version,
                url=url,
                blurb=blurb,
                licence=licence,
                extra=extra,
                plugin=plugin,
                timeout=timeout,
            )

        self.perfdata = []

        self.messages = {
            'warning': [],
            'critical': [],
            'ok': [],
        }

        self.threshold = None

    # -----------------------------------------------------------
    @property
    def shortname(self):
        """The shortname of the plugin."""

        return self._shortname

    @shortname.setter
    def shortname(self, value):
        new_name = str(value).strip()
        if not new_name:
            msg = "New shortname %r may not be empty."
            raise NagiosPluginError(msg % (value))
        self._shortname = new_name

    # -------------------------------------------------------------------------
    def as_dict(self):
        """
        Typecasting into a dictionary.

        @return: structure as dict
        @rtype:  dict

        """

        d = {
            '__class__': self.__class__.__name__,
            'shortname': self.shortname,
            'argparser': None,
            'perfdata': [],
            'messages': self.messages,
            'threshold': None,
        }

        if self.argparser:
            d['argparser'] = self.argparser.as_dict()

        for pdata in self.perfdata:
            d['perfdata'].append(pdata.as_dict())

        if self.threshold:
            d['threshold'] = self.threshold.as_dict()

        return d

    # -------------------------------------------------------------------------
    def __str__(self):
        """
        Typecasting function for translating object structure into a string.

        @return: structure as string
        @rtype:  str

        """

        return pp(self.as_dict())

    # -------------------------------------------------------------------------
    def __repr__(self):
        """Typecasting into a string for reproduction."""

        out = "<%s(" % (self.__class__.__name__)

        fields = []
        fields.append("shortname=%r" % (self.shortname))
        fields.append("argparser=%r" % (self.argparser))
        fields.append("perfdata=%r" % (self.perfdata))
        fields.append("messages=%r" % (self.messages))
        fields.append("threshold=%r" % (self.threshold))

        out += ", ".join(fields) + ")>"
        return out

    # -------------------------------------------------------------------------
    def add_perfdata(
        self, label, value, uom=None, threshold=None, warning=None, critical=None,
            min_data=None, max_data=None):
        """
        Adding a NagiosPerformance object to self.perfdata.

        @param label: the label of the performance data, mandantory
        @type label: str
        @param value: the value of the performance data, mandantory
        @type value: Number
        @param uom: the unit of measure
        @type uom: str or None
        @param threshold: an object for the warning and critical thresholds
                          if set, it overrides the warning and critical parameters
        @type threshold: NagiosThreshold or None
        @param warning: a range for the warning threshold,
                        ignored, if threshold is given
        @type warning: NagiosRange, str, Number or None
        @param critical: a range for the critical threshold,
                        ignored, if threshold is given
        @type critical: NagiosRange, str, Number or None
        @param min_data: the minimum data for performance output
        @type min_data: Number or None
        @param max_data: the maximum data for performance output
        @type max_data: Number or None

        """

        pdata = NagiosPerformance(
            label=label,
            value=value,
            uom=uom,
            threshold=threshold,
            warning=warning,
            critical=critical,
            min_data=min_data,
            max_data=max_data
        )

        self.perfdata.append(pdata)

    # -------------------------------------------------------------------------
    def add_arg(self, *names, **kwargs):
        """top level interface to my NagiosPluginArgparse object."""

        if self.argparser:
            self.argparser.add_arg(*names, **kwargs)
        else:
            log.warn("Called add_arg() without a valid NagiosPluginArgparse object.")

    # -------------------------------------------------------------------------
    def parse_args(self, args=None):
        """
        Executes self.argparser.parse_args().

        @param args: the argument strings to parse. If not given, they are
                     taken from sys.argv.
        @type args: list of str or None

        """

        if args is None:
            args = sys.argv[1:]

        if self.argparser:
            log.debug("Parsing commandline arguments: %r", args)
            self.argparser.parse_args(args)
        else:
            log.warn("Called parse_args() without a valid NagiosPluginArgparse object.")

    # -------------------------------------------------------------------------
    def getopts(self, args=None):
        """
        Wrapper for self.parse_args().

        @param args: the argument strings to parse.
        @type args: list of str or None

        """

        self.parse_args(args)

    # -------------------------------------------------------------------------
    def all_perfoutput(self):
        """Generates a string with all formatted performance data."""

        return ' '.join([x.perfoutput() for x in self.perfdata])

    # -------------------------------------------------------------------------
    def set_thresholds(self, warning=None, critical=None):
        """
        Initialisation of self.threshold as a the NagiosThreshold object.

        @param warning: the warning threshold
        @type warning: str, int, long, float or NagiosRange
        @param critical: the critical threshold
        @type critical: str, int, long, float or NagiosRange

        @return: the generated threshold object
        @rtype: NagiosThreshold

        """

        self.threshold = NagiosThreshold(
            warning=warning, critical=critical)

        return self.threshold

    # -------------------------------------------------------------------------
    def check_threshold(self, value, warning=None, critical=None):
        """
        Evaluates value against the thresholds and returns nagios.state.ok,
        nagios.state.warning or nagios.state.critical.

        The thresholds may be:
            - explicitly set by passing 'warning' and/or 'critical' parameters
              to check_threshold() or
            - explicitly set by calling set_thresholds() before check_threshold(),
              or
            - implicitly set by command-line parameters -w, -c, --critical or
              --warning, if you have run plugin.parse_args()

        @param value: the value to check
        @type value: Number
        @param warning: the warning threshold for the given value
        @type warning: NagiosRange, str or None
        @param critical: the critical threshold for the given value
        @type critical: NagiosRange, str or None

        @return: an exit value ready to pass to nagios_exit(), e.g.::

                    plugin.nagios_exit(
                            code = plugin.check_threshold(value),
                            message = (" sample result was %d" % (value)),
                    )

        @rtype: int

        """

        if not isinstance(value, Number):
            msg = "Value %r must be a number on calling check_threshold()."
            raise NagiosPluginError(msg % (value))

        if warning is not None or critical is not None:
            self.set_thresholds(
                warning=warning,
                critical=critical,
            )
        elif self.threshold:
            pass
        elif self.argparser is not None and self.argparser.has_parsed:
            self.set_thresholds(
                warning=getattr(self.argparser.args, 'warning', None),
                critical=getattr(self.argparser.args, 'critical', None),
            )
        else:
            return nagios.state.unknown

        return self.threshold.get_status(value)

    # ------------------------------------------------------------------------
    def nagios_exit(self, code, message):
        """Wrapper method for nagios.plugin.functions.nagios_exit()."""

        return nagios.plugin.functions.nagios_exit(code, message, self)

    # ------------------------------------------------------------------------
    def nagios_die(self, message):
        """Wrapper method for nagios.plugin.functions.nagios_die()."""

        return nagios.plugin.functions.nagios_die(message, self)

    # ------------------------------------------------------------------------
    def exit(self, code, message):
        """Wrapper method for nagios.plugin.functions.nagios_exit()."""

        return nagios.plugin.functions.nagios_exit(code, message, self)

    # ------------------------------------------------------------------------
    def die(self, message):
        """Wrapper method for nagios.plugin.functions.nagios_die()."""

        return nagios.plugin.functions.nagios_die(message, self)

    # -------------------------------------------------------------------------
    def max_state(self, *args):
        """Wrapper method for nagios.plugin.functions.max_state()."""

        return nagios.plugin.functions.max_state(*args)

    # -------------------------------------------------------------------------
    def max_state_alt(self, *args):
        """Wrapper method for nagios.plugin.functions.max_state_alt()."""

        return nagios.plugin.functions.max_state_alt(*args)

    # -------------------------------------------------------------------------
    def add_message(self, code, *messages):
        """Adds one ore more messages to self.messages under the appropriate
           subkey, which is defined by the code."""

        key = str(code).upper()
        if (key not in nagios.plugin.functions.ERRORS and
                code not in nagios.plugin.functions.STATUS_TEXT):
            msg = "Invalid error code %r on calling add_message()." % (code)
            raise NagiosPluginError(msg)

        if key.lower() in ('unknown', 'dependent'):
            msg = "Error code %r not supported by add_message()." % (code)
            raise NagiosPluginError(msg)

        if code in nagios.plugin.functions.STATUS_TEXT:
            key = nagios.plugin.functions.STATUS_TEXT[code]
        key = key.lower()

        if key not in self.messages:
            self.messages[key] = []
        for msg in messages:
            self.messages[key].append(msg)

    # -------------------------------------------------------------------------
    def check_messages(
            self, critical=None, warning=None, ok=None, join=' ', join_all=False):
        """
        Method to check the given messages and the messages under self.messages
        and to returning an appropriate return code and/or result message.

        @param critical: a list or a single critical message
        @type critical: list of str or str or None
        @param warning: a list or a single warning message
        @type warning: list of str or str or None
        @param ok: a list or a single message
        @type ok: list of str or str or None
        @param join: a string used to join the relevant list to generate the
                     message string returned. I.e. if the 'critical' list
                     is non-empty, check_messages would return
                     as the result message::

                        join.join(critical)

        @type join: str
        @param join_all: by default only one, the appropriate set of messages
                         are joined and returned in the result message. If the
                         result is critical, only the 'critical' messages
                         are included. If join_all is supplied, however,
                         it will be used as a string to join the resultant
                         critical, warning, and ok messages together i.e. all
                         messages are joined and returned.
        @type join_all: str

        @return: the appropriate nagios return code and the appropriate message
        @rtype: tuple

        """

        args = {
            'join': join,
            'join_all': join_all,
        }

        if critical is None:
            critical = []
        elif isinstance(critical, str):
            critical = [critical]
        for msg in self.messages['critical']:
            critical.append(msg)
        args['critical'] = critical

        if warning is None:
            warning = []
        elif isinstance(warning, str):
            warning = [warning]
        for msg in self.messages['warning']:
            warning.append(msg)
        args['warning'] = warning

        if ok is None:
            ok = []
        elif isinstance(ok, str):
            ok = [ok]
        for msg in self.messages['ok']:
            ok.append(msg)
        if ok:
            args['ok'] = ok

        log.debug(
            "Arguments for nagios.plugin.functions.check_messages():\n%r", args)

        return nagios.plugin.functions.check_messages(**args)

    # -------------------------------------------------------------------------
    def read_file(self, filename, timeout=2, quiet=False):
        """
        Reads the content of the given filename.

        @raise IOError: if file doesn't exists or isn't readable
        @raise PbReadTimeoutError: on timeout reading the file

        @param filename: name of the file to read
        @type filename: str
        @param timeout: the amount in seconds when this method should timeout
        @type timeout: int
        @param quiet: increases the necessary verbosity level to
                      put some debug messages
        @type quiet: bool

        @return: file content
        @rtype:  str

        """

        def read_alarm_caller(signum, sigframe):
            '''
            This nested function will be called in event of a timeout

            @param signum:   the signal number (POSIX) which happend
            @type signum:    int
            @param sigframe: the frame of the signal
            @type sigframe:  object
            '''

            raise NPReadTimeoutError(timeout, filename)

        timeout = abs(int(timeout))

        if not os.path.isfile(filename):
            raise IOError(errno.ENOENT, "File doesn't exists", filename)
        if not os.access(filename, os.R_OK):
            raise IOError(errno.EACCES, 'Read permission denied', filename)

        if not quiet:
            log.debug("Reading file content of %r ...", filename)

        signal.signal(signal.SIGALRM, read_alarm_caller)
        signal.alarm(timeout)

        content = ''
        fh = open(filename, 'r')
        for line in fh.readlines():
            content += line
        fh.close()

        signal.alarm(0)

        return content

    # -------------------------------------------------------------------------
    def handle_error(
            self, error_message=None, exception_name=None, do_traceback=False):
        """
        Handle an error gracefully.

        Print a traceback and continue.

        @param error_message: the error message to display
        @type error_message: str
        @param exception_name: name of the exception class
        @type exception_name: str
        @param do_traceback: allways show a traceback
        @type do_traceback: bool

        """

        msg = 'Exception happened: '
        if exception_name is not None:
            exception_name = exception_name.strip()
            if exception_name:
                msg = exception_name + ': '
            else:
                msg = ''
        if error_message:
            msg += str(error_message)
        else:
            msg += 'undefined error.'

        root_log = logging.getLogger()
        has_handlers = False
        if root_log.handlers:
            has_handlers = True

        if has_handlers:
            log.error(msg)
            if do_traceback:
                log.error(traceback.format_exc())
        else:
            curdate = datetime.datetime.now()
            curdate_str = "[" + curdate.isoformat(' ') + "]: "
            msg = curdate_str + msg + "\n"
            sys.stderr.write(msg)
            if do_traceback:
                traceback.print_exc()

        return
Ejemplo n.º 10
0
    def __init__(self,
                 label,
                 value,
                 uom=None,
                 threshold=None,
                 warning=None,
                 critical=None,
                 min_data=None,
                 max_data=None):
        """
        Initialisation of the NagiosPerformance object.

        @param label: the label of the performance data, mandantory
        @type label: str
        @param value: the value of the performance data, mandantory
        @type value: Number
        @param uom: the unit of measure
        @type uom: str or None
        @param threshold: an object for the warning and critical thresholds
                          if set, it overrides the warning and critical parameters
        @type threshold: NagiosThreshold or None
        @param warning: a range for the warning threshold,
                        ignored, if threshold is given
        @type warning: NagiosRange, str, Number or None
        @param critical: a range for the critical threshold,
                        ignored, if threshold is given
        @type critical: NagiosRange, str, Number or None
        @param min_data: the minimum data for performance output
        @type min_data: Number or None
        @param max_data: the maximum data for performance output
        @type max_data: Number or None

        """

        self._label = str(label).strip()
        """
        @ivar: the label of the performance data
        @type: str
        """
        if label is None or self._label == '':
            raise NagiosPerformanceError(
                "Empty label %r for NagiosPerformance given." % (label))

        self._value = value
        """
        @ivar: the value of the performance data
        @type: Number
        """
        if not isinstance(value, Number):
            raise NagiosPerformanceError(
                "Wrong value %r for NagiosPerformance given." % (value))

        self._uom = ''
        """
        @ivar: the unit of measure
        @type: str
        """
        if uom is not None:
            # remove all whitespaces
            self._uom = re_ws.sub('', str(uom))

        warn_range = NagiosRange()
        if warning:
            warn_range = NagiosRange(warning)

        crit_range = NagiosRange()
        if critical:
            crit_range = NagiosRange(critical)

        self._threshold = None
        """
        @ivar: the threshold object containing the warning and the
               critical threshold
        @type: NagiosThreshold
        """
        if isinstance(threshold, NagiosThreshold):
            self._threshold = threshold
        elif threshold is not None:
            raise NagiosPerformanceError(
                "The given threshold %r is neither None nor a NagiosThreshold object."
                % (threshold))
        else:
            self._threshold = NagiosThreshold(warning=warn_range,
                                              critical=crit_range)

        self._min_data = None
        """
        @ivar: the minimum data for performance output
        @type: Number or None
        """
        if min_data is not None:
            if not isinstance(min_data, Number):
                raise NagiosPerformanceError(
                    "The given min_data %r is not None and not a Number." %
                    (min_data))
            else:
                self._min_data = min_data

        self._max_data = None
        """
        @ivar: the maximum data for performance output
        @type: Number or None
        """
        if max_data is not None:
            if not isinstance(max_data, Number):
                raise NagiosPerformanceError(
                    "The given max_data %r is not None and not a Number." %
                    (max_data))
            else:
                self._max_data = max_data
Ejemplo n.º 11
0
    def __call__(self):
        """
        Method to call the plugin directly.
        """

        self.parse_args()
        self.init_root_logger()

        if not self.argparser.args.vg:
            self.die("No volume group to check given.")
        self._vg = self.argparser.args.vg

        if self.verbose > 2:
            log.debug("Current object:\n%s", pp(self.as_dict()))

        # ----------------------------------------------------------
        # Parameters for check_free
        crit = 0
        crit_is_abs = True
        warn = 0
        warn_is_abs = True

        if not self.check_state:

            match_pc = re_number_percent.search(self.argparser.args.critical)
            match_abs = re_number_abs.search(self.argparser.args.critical)

            if match_pc:
                crit = int(match_pc.group(1))
                crit_is_abs = False
            elif match_abs:
                crit = int(match_abs.group(1))
            else:
                self.die("Invalid critical value %r." %
                         (self.argparser.args.critical))
                return

            match_pc = re_number_percent.search(self.argparser.args.warning)
            match_abs = re_number_abs.search(self.argparser.args.warning)

            if match_pc:
                warn = int(match_pc.group(1))
                warn_is_abs = False
            elif match_abs:
                warn = int(match_abs.group(1))
            else:
                self.die("Invalid warning value %r." %
                         (self.argparser.args.warning))
                return

        # ----------------------------------------------------------
        # Getting current state of VG
        vg_state = LvmVgState(plugin=self,
                              vg=self.vg,
                              vgs_cmd=self.vgs_cmd,
                              verbose=self.verbose,
                              timeout=self.argparser.args.timeout)

        try:
            vg_state.get_data()
        except (ExecutionTimeoutError, VgNotExistsError) as e:
            self.die(str(e))
        except CalledProcessError as e:
            msg = "The %r command returned %d with the message: %s" % (
                self.vgs_cmd, e.returncode, e.output)
            self.die(msg)

        if self.verbose > 1:
            log.debug("Got a state of the volume group %r:\n%s", self.vg,
                      vg_state)

        # ----------------------------------------------
        if self.check_state:

            self.add_message(nagios.state.ok,
                             ("Volume group %r seems to be OK." % (self.vg)))

            if 'r' in vg_state.attr:
                self.add_message(nagios.state.warning,
                                 ("Volume group %r is in a read-only state." %
                                  (self.vg)))

            if 'z' not in vg_state.attr:
                self.add_message(nagios.state.warning,
                                 ("Volume group %r is not resizeable." %
                                  (self.vg)))

            if 'p' in vg_state.attr:
                self.add_message(
                    nagios.state.critical,
                    (("One or more physical volumes belonging to the "
                      "volume group %r are missing from the system.") %
                     (self.vg)))

            if self.verbose:
                self.out("Attributes of VG %r: %s" %
                         (self.vg, vg_state.attr_str))

            (state, msg) = self.check_messages()
            self.exit(state, msg)

            # Only for the blinds:
            return

        # ----------------------------------------------
        # And now check free space (or whatever)

        if not vg_state.size_mb:
            self.die("Cannot detect absolute size of volume group %r." %
                     (self.vg))

        c_free_abs = 0
        c_free_pc = 0
        c_used_abs = 0
        c_used_pc = 0
        if crit_is_abs:
            c_free_abs = crit
            c_used_abs = vg_state.size_mb - crit
            c_free_pc = float(crit) / float(vg_state.size_mb) * 100
            c_used_pc = float(c_used_abs) / float(vg_state.size_mb) * 100
        else:
            c_free_pc = float(crit)
            c_used_pc = 100.0 - c_free_pc
            c_free_abs = int(
                math.ceil(c_free_pc * float(vg_state.size_mb) / 100))
            c_used_abs = vg_state.size_mb - c_free_abs

        w_free_abs = 0
        w_free_pc = 0
        w_used_abs = 0
        w_used_pc = 0
        if warn_is_abs:
            w_free_abs = warn
            w_used_abs = vg_state.size_mb - warn
            w_free_pc = float(warn) / float(vg_state.size_mb) * 100
            w_used_pc = float(w_used_abs) / float(vg_state.size_mb) * 100
        else:
            w_free_pc = float(warn)
            w_used_pc = 100.0 - w_free_pc
            w_free_abs = int(
                math.ceil(w_free_pc * float(vg_state.size_mb) / 100))
            w_used_abs = vg_state.size_mb - w_free_abs

        if c_free_abs > w_free_abs:
            self.die(
                "The warning threshold must be greater than the critical threshold."
            )

        th_free_abs = NagiosThreshold(warning="@%d" % (w_free_abs),
                                      critical="@%d" % (c_free_abs))
        th_used_abs = NagiosThreshold(warning="%d" % (w_used_abs),
                                      critical="%d" % (c_used_abs))
        th_free_pc = NagiosThreshold(warning="@%d" % (w_free_pc),
                                     critical="@%d" % (c_free_pc))
        th_used_pc = NagiosThreshold(warning="%f" % (w_used_pc),
                                     critical="%f" % (c_used_pc))

        if self.verbose:
            self.out("VG %r total size: %8d MiBytes." %
                     (self.vg, vg_state.size_mb))
            self.out("VG %r used size:  %8d MiBytes (%0.2f%%)." %
                     (self.vg, vg_state.used_mb, vg_state.percent_used))
            self.out("VG %r free size:  %8d MiBytes (%0.2f%%)." %
                     (self.vg, vg_state.free_mb, vg_state.percent_free))

        if self.verbose > 2:
            log.debug("Thresholds free MBytes:\n%s", pp(th_free_abs.as_dict()))
            log.debug("Thresholds free percent:\n%s", pp(th_free_pc.as_dict()))
            log.debug("Thresholds used MBytes:\n%s", pp(th_used_abs.as_dict()))
            log.debug("Thresholds used percent:\n%s", pp(th_used_pc.as_dict()))

        self.add_perfdata(label='total_size', value=vg_state.size_mb, uom='MB')
        self.add_perfdata(label='free_size',
                          value=vg_state.free_mb,
                          uom='MB',
                          threshold=th_free_abs)
        self.add_perfdata(label='free_percent',
                          value=float("%0.2f" % (vg_state.percent_free)),
                          uom='%',
                          threshold=th_free_pc)
        self.add_perfdata(label='alloc_size',
                          value=vg_state.used_mb,
                          uom='MB',
                          threshold=th_used_abs)
        self.add_perfdata(label='alloc_percent',
                          value=float("%0.2f" % (vg_state.percent_used)),
                          uom='%',
                          threshold=th_used_pc)

        state = th_free_abs.get_status(vg_state.free_mb)

        out = "%d MiB total, %d MiB free (%0.1f%%), %d MiB allocated (%0.1f%%)" % (
            vg_state.size_mb, vg_state.free_mb, vg_state.percent_free,
            vg_state.used_mb, vg_state.percent_used)

        self.exit(state, out)