Esempio 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)))
Esempio n. 2
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)))
Esempio n. 3
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
Esempio n. 4
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)
Esempio n. 5
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)