def _check_and_response(value, warning, critical):
    """Checks a value and responds with an appropriate code."""

    try:
        if not _check_range(critical, value):
            _response(_STATUS_CRITICAL, str(value))
        elif not _check_range(warning, value):
            _response(_STATUS_WARNING, str(value))
        else:
            _response(_STATUS_OK, str(value))
    except _RangeFormatError as e:
        _response(_STATUS_UNKNOWN, str(e))
def main():
    """The script's main function."""

    try:
        parser = argparse.ArgumentParser(
            description="XBee Nagios plugin")

        parser.add_argument("host", help="host")
        parser.add_argument("metric", choices=["temperature"], help="metric name")

        parser.add_argument("-w", "--warning", metavar="VALUE",
            help="warning threshold", required=True)

        parser.add_argument("-c", "--critical", metavar="VALUE",
            help="critical threshold", required=True)

        args = parser.parse_args()

        if args.metric == "temperature":
            _check_and_response(_get_temperature(args.host),
                args.warning, args.critical)
        else:
            raise LogicalError()
    except Exception as e:
        _response(_STATUS_CRITICAL if isinstance(e, Error) else _STATUS_UNKNOWN, str(e))
    def __handle_request(self):
        """Handles a request."""

        try:
            request = json.loads(self._read_buffer.decode("utf-8"))

            if (
                "method" not in request or
                any(type(key) is not str for key in request.keys()) or
                any(type(value) is not str for value in request.values())
            ):
                raise ValueError()
        except (UnicodeDecodeError, ValueError):
            LOG.error("%s: got an invalid request %s.", self, bytes(self._read_buffer))
            self.close()
            return

        LOG.info("%s: request %s", self, request)

        try:
            reply = { "result": monitor.request.handle(request.pop("method"), request) }
        except Exception as e:
            (LOG.warning if isinstance(e, Error) else LOG.error)(
                "%s: request failed: %s", self, e)

            reply = { "error": str(e) if isinstance(e, Error) else "Internal error" }

        response = json.dumps(reply).encode("utf-8")
        if self._write(struct.pack(self.__message_size_format, len(response)) + response):
            self.close()
Example #4
0
    def _shell_command_full(self):
        """
        Generates a shell command which execution is equal to self.execute()
        including handling of errors in the middle of the process pipe.
        """

        command = BytesIO()

        pipe_ok_statuses = []
        self._shell_command(command, pipe_ok_statuses)

        if len(pipe_ok_statuses) == 1:
            return command.getvalue()

        command.write(b"; statuses=(${PIPESTATUS[@]});")

        for process_id, ok_statuses in enumerate(pipe_ok_statuses):
            if process_id == len(pipe_ok_statuses) - 1:
                command.write(
                    psys.b(" exit ${{statuses[{0}]}};".format(process_id)))
            else:
                command.write(
                    psys.b(" case ${{statuses[{0}]}} in".format(process_id)))
                if ok_statuses:
                    command.write(
                        psys.b(" {0});;".format("|".join(
                            str(status) for status in ok_statuses))))
                command.write(b" *) exit 128;; esac;")

        return b"bash -c '" + command.getvalue().replace(b"'",
                                                         b"""'"'"'""") + b"'"
Example #5
0
    def _shell_command_full(self):
        """
        Generates a shell command which execution is equal to self.execute()
        including handling of errors in the middle of the process pipe.
        """

        command = BytesIO()

        pipe_ok_statuses = []
        self._shell_command(command, pipe_ok_statuses)

        if len(pipe_ok_statuses) == 1:
            return command.getvalue()

        command.write(b"; statuses=(${PIPESTATUS[@]});")

        for process_id, ok_statuses in enumerate(pipe_ok_statuses):
            if process_id == len(pipe_ok_statuses) - 1:
                command.write(psys.b(" exit ${{statuses[{0}]}};".format(process_id)))
            else:
                command.write(psys.b(" case ${{statuses[{0}]}} in".format(process_id)))
                if ok_statuses:
                    command.write(psys.b(" {0});;".format("|".join(str(status) for status in ok_statuses))))
                command.write(b" *) exit 128;; esac;")

        return b"bash -c '" + command.getvalue().replace(b"'", b"""'"'"'""") + b"'"
Example #6
0
def test_pid(test):
    """Tests pid()."""

    process = sh.sh("-c", "echo $$")

    with pytest.raises(psh.InvalidProcessState):
        process.pid()

    assert process.execute().stdout().strip() == str(process.pid())
Example #7
0
def test_pid(test):
    """Tests pid()."""

    process = sh.sh("-c", "echo $$")

    with pytest.raises(psh.InvalidProcessState):
        process.pid()

    assert process.execute().stdout().strip() == str(process.pid())
Example #8
0
def test_iterator_input(test):
    """Tests process input from string."""

    stdout = "\n".join(str(i) for i in range(0, 10))

    def func():
        for i in range(0, 10):
            yield "\n" + str(i) if i else str(i)

    assert sh.cat(_stdin=func()).execute().stdout() == stdout
Example #9
0
def test_iterator_input(test):
    """Tests process input from string."""

    stdout = "\n".join(str(i) for i in range(0, 10))

    def func():
        for i in range(0, 10):
            yield "\n" + str(i) if i else str(i)

    assert sh.cat(_stdin=func()).execute().stdout() == stdout
Example #10
0
def _get_arg_value(value, shell):
    """Returns an argument string value."""

    if type(value) in (bytes, str):
        return value
    elif type(value) in (int, float) + (tuple() if PY3 else (long,)):
        return str(value)
    elif shell and isinstance(value, Process):
        return value._shell_command_full()
    else:
        raise InvalidArgument("Invalid argument: command arguments must be basic types only")
Example #11
0
def _get_arg_value(value, shell):
    """Returns an argument string value."""

    if type(value) in (bytes, str):
        return value
    elif type(value) in (int, float) + (tuple() if PY3 else (long, )):
        return str(value)
    elif shell and isinstance(value, Process):
        return value._shell_command_full()
    else:
        raise InvalidArgument(
            "Invalid argument: command arguments must be basic types only")
def test_output_iteration_with_large_data(test):
    """
    Tests iteration over process' output with large amount of data
    (more than any buffer size).
    """

    stdin = [str(i) + "\n" for i in range(0, 100000)]

    with sh.cat(_stdin="".join(stdin)) as process:
        stdout = [line for line in process]

    assert stdout == stdin
Example #13
0
def test_output_iteration_with_large_data(test):
    """
    Tests iteration over process' output with large amount of data
    (more than any buffer size).
    """

    stdin = [str(i) + "\n" for i in range(0, 100000)]

    with sh.cat(_stdin="".join(stdin)) as process:
        stdout = [line for line in process]

    assert stdout == stdin
Example #14
0
    def wait(self, check_status=False, kill=None):
        """Waits for the process termination.

        :param check_status: if :py:const:`True`, check the process status
            code (see :ref:`exit-codes`) and other (communication) errors and
            raise an exception if any error occurred.
        :type check_status: bool

        :param kill: if is not :py:const:`None`, kills the process with the
            ``kill(signal = kill)`` and waits for its termination.
        :type kill: int

        :returns: the process exit status
        """

        if self.__state < _PROCESS_STATE_RUNNING:
            raise InvalidProcessState("Process is not running")

        LOG.debug(
            "Waiting for %s termination%s...", self,
            "" if kill is None else " killing it with {0} signal".format(kill))

        if kill is not None:
            while self.kill(kill):
                if self.__join_threads(0.1):
                    break

        self.__join_threads()

        if self.__piped_from_process():
            self.__stdin_source.wait(check_status=check_status, kill=kill)

        if check_status:
            if self.__error is not None:
                raise self.__error

            if self.__status not in self.__ok_statuses:
                raise ExecutionError(str(self), self.__status,
                                     self.raw_stdout(), self.raw_stderr())

        return self.__status
Example #15
0
    def wait(self, check_status=False, kill=None):
        """Waits for the process termination.

        :param check_status: if :py:const:`True`, check the process status
            code (see :ref:`exit-codes`) and other (communication) errors and
            raise an exception if any error occurred.
        :type check_status: bool

        :param kill: if is not :py:const:`None`, kills the process with the
            ``kill(signal = kill)`` and waits for its termination.
        :type kill: int

        :returns: the process exit status
        """

        if self.__state < _PROCESS_STATE_RUNNING:
            raise InvalidProcessState("Process is not running")

        LOG.debug("Waiting for %s termination%s...",
            self, "" if kill is None else " killing it with {0} signal".format(kill))

        if kill is not None:
            while self.kill(kill):
                if self.__join_threads(0.1):
                    break

        self.__join_threads()

        if self.__piped_from_process():
            self.__stdin_source.wait(
                check_status=check_status, kill=kill)

        if check_status:
            if self.__error is not None:
                raise self.__error

            if self.__status not in self.__ok_statuses:
                raise ExecutionError(str(self),
                    self.__status, self.raw_stdout(), self.raw_stderr())

        return self.__status
Example #16
0
def test_command_arguments(test):
    """Tests command argument parsing."""

    process = sh.test()
    assert process.command() == ["test"]
    assert str(process) == "test"
    assert bytes(process) == psys.b(str(process))

    process = sh.complex_command_name()
    assert process.command() == ["complex-command-name"]
    assert str(process) == "complex-command-name"
    assert bytes(process) == psys.b(str(process))

    process = sh("complex command name")("arg1", "arg2")
    assert process.command() == ["complex command name", "arg1", "arg2"]
    assert str(process) == "'complex command name' arg1 arg2"
    assert bytes(process) == psys.b(str(process))

    process = sh.test(b"arg", b"space arg", b"carriage\rline", b"line\narg",
                      b"tab\targ", br"slash\arg", b"quote'arg", b'quote"arg',
                      psys.b("тест"), psys.b("тест тест"), "arg", "space arg",
                      "carriage\rline", "line\narg", "tab\targ", r"slash\arg",
                      "quote'arg", 'quote"arg', "тест", "тест тест", 3, 2**128,
                      2.0)
    assert process.command() == [
        "test", b"arg", b"space arg", b"carriage\rline", b"line\narg",
        b"tab\targ", br"slash\arg", b"quote'arg", b'quote"arg',
        psys.b("тест"),
        psys.b("тест тест"), "arg", "space arg", "carriage\rline", "line\narg",
        "tab\targ", r"slash\arg", "quote'arg", 'quote"arg', "тест",
        "тест тест", "3", "340282366920938463463374607431768211456", "2.0"
    ]
    assert str(process) == (
        "test "
        r"""arg 'space arg' 'carriage\rline' 'line\narg' 'tab\targ' 'slash\\arg' "quote'arg" 'quote"arg' \xd1\x82\xd0\xb5\xd1\x81\xd1\x82 '\xd1\x82\xd0\xb5\xd1\x81\xd1\x82 \xd1\x82\xd0\xb5\xd1\x81\xd1\x82' """
        r"""arg 'space arg' 'carriage\rline' 'line\narg' 'tab\targ' 'slash\\arg' 'quote\'arg' 'quote"arg' тест 'тест тест' """
        "3 340282366920938463463374607431768211456 2.0")
    assert bytes(process) == psys.b(str(process))

    process = sh.test("space arg", s="short_arg")
    assert process.command() == ["test", "-s", "short_arg", "space arg"]
    assert str(process) == "test -s short_arg 'space arg'"
    assert bytes(process) == psys.b(str(process))

    process = sh.test("arg", long_long_arg="long arg")
    assert process.command() == ["test", "--long-long-arg", "long arg", "arg"]
    assert str(process) == "test --long-long-arg 'long arg' arg"
    assert bytes(process) == psys.b(str(process))

    process = sh.test("arg", bool_arg=True)
    assert process.command() == ["test", "--bool-arg", "arg"]
    assert str(process) == "test --bool-arg arg"
    assert bytes(process) == psys.b(str(process))

    process = sh.test("arg", bool_arg=False)
    assert process.command() == ["test", "arg"]
    assert str(process) == "test arg"
    assert bytes(process) == psys.b(str(process))
Example #17
0
    def __communicate(self, poll):
        """Communicates with the process and waits for its termination."""

        pipe_map = {}
        poll_objects = 0

        # Configure the poll object and pipes -->
        poll.register(self.__termination_fd, poll.POLLIN)
        poll_objects += 1

        for pipe in self.__pipes:
            fd = pipe.read if pipe.output else pipe.write
            if fd is None:
                continue

            pipe_map[fd] = pipe

            flags = eintr_retry(fcntl.fcntl)(fd, fcntl.F_GETFL)
            eintr_retry(fcntl.fcntl)(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)

            poll.register(fd, poll.POLLIN if pipe.output else poll.POLLOUT)
            pipe.close(read=not pipe.output, write=pipe.output)
            poll_objects += 1
        # Configure the poll object and pipes <--

        # Communicate with the process -->
        stdin = None

        while poll_objects:
            events = poll.poll()

            for fd, flags in events:
                # Process termination
                if fd == self.__termination_fd:
                    if self.__wait_for_output:
                        poll.unregister(self.__termination_fd)
                        poll_objects -= 1
                        continue
                    else:
                        poll_objects = 0
                        break

                pipe = pipe_map[fd]

                # stdin
                if pipe.source == psys.STDIN_FILENO:
                    if stdin is None:
                        try:
                            stdin = next(self.__stdin_generator)

                            try:
                                if type(stdin) not in (bytes, str):
                                    raise TypeError("must be a string")

                                stdin = psys.b(stdin)
                            except Exception as e:
                                raise InvalidArgument("Invalid stdin data: {0}", e)
                        except StopIteration:
                            pass
                        except Exception as e:
                            self.__error = e
                            stdin = None

                    if stdin is None:
                        poll.unregister(fd)
                        poll_objects -= 1
                        pipe.close()
                    else:
                        try:
                            size = eintr_retry(os.write)(fd, stdin)
                        except EnvironmentError as e:
                            # The process closed its stdin
                            if e.errno == errno.EPIPE:
                                poll.unregister(fd)
                                poll_objects -= 1
                                pipe.close()
                            else:
                                raise e
                        else:
                            if size == len(stdin):
                                stdin = None
                            else:
                                stdin = stdin[size:]
                # stdout/stderr
                elif pipe.source in (psys.STDOUT_FILENO, psys.STDERR_FILENO):
                    data = eintr_retry(os.read)(fd, psys.BUFSIZE)

                    if data:
                        self.__on_output(pipe.source, data)
                    else:
                        poll.unregister(fd)
                        poll_objects -= 1
                else:
                    raise LogicalError()
        # Communicate with the process <--

        if not self.__wait_for_output:
            # The process has terminated, but we should continue communication
            # to get output that we haven't got from it yet. But we must do it
            # wisely, because the process might fork() itself, so we'll read
            # its child's output forever.

            # Maximum output size after process termination (bigger than any
            # pipe buffer size).
            max_data_size = 1024 * 1024

            for pipe in self.__pipes:
                if (
                    pipe.source in (psys.STDOUT_FILENO, psys.STDERR_FILENO) and
                    pipe.read is not None
                ):
                    size = 0

                    while size < max_data_size:
                        try:
                            data = eintr_retry(os.read)(
                                pipe.read, min(psys.BUFSIZE, max_data_size - size))
                        except EnvironmentError as e:
                            if e.errno != errno.EAGAIN:
                                raise e

                            if not self.__truncate_output:
                                self.__error = ProcessOutputWasTruncated(
                                    str(self), self.__status,
                                    self.__stdout.getvalue(), self.__stderr.getvalue())

                            break
                        else:
                            if data:
                                size += len(data)
                                self.__on_output(pipe.source, data)
                            else:
                                break
Example #18
0
    def __communicate(self, poll):
        """Communicates with the process and waits for its termination."""

        pipe_map = {}
        poll_objects = 0

        # Configure the poll object and pipes -->
        poll.register(self.__termination_fd, poll.POLLIN)
        poll_objects += 1

        for pipe in self.__pipes:
            fd = pipe.read if pipe.output else pipe.write
            if fd is None:
                continue

            pipe_map[fd] = pipe

            flags = eintr_retry(fcntl.fcntl)(fd, fcntl.F_GETFL)
            eintr_retry(fcntl.fcntl)(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)

            poll.register(fd, poll.POLLIN if pipe.output else poll.POLLOUT)
            pipe.close(read=not pipe.output, write=pipe.output)
            poll_objects += 1
        # Configure the poll object and pipes <--

        # Communicate with the process -->
        stdin = None

        while poll_objects:
            events = poll.poll()

            for fd, flags in events:
                # Process termination
                if fd == self.__termination_fd:
                    if self.__wait_for_output:
                        poll.unregister(self.__termination_fd)
                        poll_objects -= 1
                        continue
                    else:
                        poll_objects = 0
                        break

                pipe = pipe_map[fd]

                # stdin
                if pipe.source == psys.STDIN_FILENO:
                    if stdin is None:
                        try:
                            stdin = next(self.__stdin_generator)

                            try:
                                if type(stdin) not in (bytes, str):
                                    raise TypeError("must be a string")

                                stdin = psys.b(stdin)
                            except Exception as e:
                                raise InvalidArgument(
                                    "Invalid stdin data: {0}", e)
                        except StopIteration:
                            pass
                        except Exception as e:
                            self.__error = e
                            stdin = None

                    if stdin is None:
                        poll.unregister(fd)
                        poll_objects -= 1
                        pipe.close()
                    else:
                        try:
                            size = eintr_retry(os.write)(fd, stdin)
                        except EnvironmentError as e:
                            # The process closed its stdin
                            if e.errno == errno.EPIPE:
                                poll.unregister(fd)
                                poll_objects -= 1
                                pipe.close()
                            else:
                                raise e
                        else:
                            if size == len(stdin):
                                stdin = None
                            else:
                                stdin = stdin[size:]
                # stdout/stderr
                elif pipe.source in (psys.STDOUT_FILENO, psys.STDERR_FILENO):
                    data = eintr_retry(os.read)(fd, psys.BUFSIZE)

                    if data:
                        self.__on_output(pipe.source, data)
                    else:
                        poll.unregister(fd)
                        poll_objects -= 1
                else:
                    raise LogicalError()
        # Communicate with the process <--

        if not self.__wait_for_output:
            # The process has terminated, but we should continue communication
            # to get output that we haven't got from it yet. But we must do it
            # wisely, because the process might fork() itself, so we'll read
            # its child's output forever.

            # Maximum output size after process termination (bigger than any
            # pipe buffer size).
            max_data_size = 1024 * 1024

            for pipe in self.__pipes:
                if (pipe.source in (psys.STDOUT_FILENO, psys.STDERR_FILENO)
                        and pipe.read is not None):
                    size = 0

                    while size < max_data_size:
                        try:
                            data = eintr_retry(os.read)(
                                pipe.read,
                                min(psys.BUFSIZE, max_data_size - size))
                        except EnvironmentError as e:
                            if e.errno != errno.EAGAIN:
                                raise e

                            if not self.__truncate_output:
                                self.__error = ProcessOutputWasTruncated(
                                    str(self), self.__status,
                                    self.__stdout.getvalue(),
                                    self.__stderr.getvalue())

                            break
                        else:
                            if data:
                                size += len(data)
                                self.__on_output(pipe.source, data)
                            else:
                                break
Example #19
0
def e(error):
    """Returns an exception error string."""

    return os.strerror(error.errno) if isinstance(error, EnvironmentError) else str(error)
Example #20
0
 def __init__(self, *args, **kwargs):
     message, args = str(args[0]), args[1:]
     super(Error, self).__init__(
         message.format(*args, **kwargs) if args or kwargs else message)
Example #21
0
 def func():
     for i in range(0, 10):
         yield "\n" + str(i) if i else str(i)
Example #22
0
def test_command_arguments(test):
    """Tests command argument parsing."""

    process = sh.test()
    assert process.command() == [ "test" ]
    assert str(process) == "test"
    assert bytes(process) == psys.b(str(process))

    process = sh.complex_command_name()
    assert process.command() == [ "complex-command-name" ]
    assert str(process) == "complex-command-name"
    assert bytes(process) == psys.b(str(process))

    process = sh("complex command name")("arg1", "arg2")
    assert process.command() == [ "complex command name", "arg1", "arg2" ]
    assert str(process) == "'complex command name' arg1 arg2"
    assert bytes(process) == psys.b(str(process))

    process = sh.test(
        b"arg", b"space arg", b"carriage\rline", b"line\narg", b"tab\targ", br"slash\arg", b"quote'arg", b'quote"arg', psys.b("тест"), psys.b("тест тест"),
        "arg", "space arg", "carriage\rline", "line\narg", "tab\targ", r"slash\arg", "quote'arg", 'quote"arg', "тест", "тест тест",
        3, 2 ** 128, 2.0
    )
    assert process.command() == [ "test",
        b"arg", b"space arg", b"carriage\rline", b"line\narg", b"tab\targ", br"slash\arg", b"quote'arg", b'quote"arg', psys.b("тест"), psys.b("тест тест"),
        "arg", "space arg", "carriage\rline", "line\narg", "tab\targ", r"slash\arg", "quote'arg", 'quote"arg', "тест", "тест тест",
        "3", "340282366920938463463374607431768211456", "2.0"
    ]
    assert str(process) == ("test "
        r"""arg 'space arg' 'carriage\rline' 'line\narg' 'tab\targ' 'slash\\arg' "quote'arg" 'quote"arg' \xd1\x82\xd0\xb5\xd1\x81\xd1\x82 '\xd1\x82\xd0\xb5\xd1\x81\xd1\x82 \xd1\x82\xd0\xb5\xd1\x81\xd1\x82' """
        r"""arg 'space arg' 'carriage\rline' 'line\narg' 'tab\targ' 'slash\\arg' 'quote\'arg' 'quote"arg' тест 'тест тест' """
        "3 340282366920938463463374607431768211456 2.0"
    )
    assert bytes(process) == psys.b(str(process))

    process = sh.test("space arg", s = "short_arg")
    assert process.command() == [ "test", "-s", "short_arg", "space arg" ]
    assert str(process) == "test -s short_arg 'space arg'"
    assert bytes(process) == psys.b(str(process))

    process = sh.test("arg", long_long_arg = "long arg")
    assert process.command() == [ "test", "--long-long-arg", "long arg", "arg" ]
    assert str(process) == "test --long-long-arg 'long arg' arg"
    assert bytes(process) == psys.b(str(process))

    process = sh.test("arg", bool_arg = True)
    assert process.command() == [ "test", "--bool-arg", "arg" ]
    assert str(process) == "test --bool-arg arg"
    assert bytes(process) == psys.b(str(process))

    process = sh.test("arg", bool_arg = False)
    assert process.command() == [ "test", "arg" ]
    assert str(process) == "test arg"
    assert bytes(process) == psys.b(str(process))
Example #23
0
File: __init__.py Project: wd5/psys
def e(error):
    """Returns an exception error string."""

    return os.strerror(error.errno) if isinstance(error, EnvironmentError) else str(error)
Example #24
0
 def func():
     for i in range(0, 10):
         yield "\n" + str(i) if i else str(i)