def run(self, cmd, timeout=None, quote=False, call_line_handler_func=False):
        """
        Note: This function is based on paramiko's exec_command()
        method.

        :param timeout: How long to wait (in seconds) for the command to finish (optional).
        :type timeout: ``float``

        :param call_line_handler_func: True to call handle_stdout_line_func function for each line
                                       of received stdout and handle_stderr_line_func for each
                                       line of stderr.
        :type call_line_handler_func: ``bool``
        """

        if quote:
            cmd = quote_unix(cmd)

        extra = {"_cmd": cmd}
        self.logger.info("Executing command", extra=extra)

        # Use the system default buffer size
        bufsize = -1

        transport = self.client.get_transport()
        chan = transport.open_session()

        start_time = time.time()
        if cmd.startswith("sudo"):
            # Note that fabric does this as well. If you set pty, stdout and stderr
            # streams will be combined into one.
            # NOTE: If pty is used, every new line character \n will be converted to \r\n which
            # isn't desired. Because of that we sanitize the output and replace \r\n with \n at the
            # bottom of this method
            uses_pty = True
            chan.get_pty()
        else:
            uses_pty = False
        chan.exec_command(cmd)

        stdout = StringIO()
        stderr = StringIO()

        # Create a stdin file and immediately close it to prevent any
        # interactive script from hanging the process.
        stdin = chan.makefile("wb", bufsize)
        stdin.close()

        # Receive all the output
        # Note #1: This is used instead of chan.makefile approach to prevent
        # buffering issues and hanging if the executed command produces a lot
        # of output.
        #
        # Note #2: If you are going to remove "ready" checks inside the loop
        # you are going to have a bad time. Trying to consume from a channel
        # which is not ready will block for indefinitely.
        exit_status_ready = chan.exit_status_ready()

        if exit_status_ready:
            stdout_data = self._consume_stdout(
                chan=chan, call_line_handler_func=call_line_handler_func
            )
            stdout_data = stdout_data.getvalue()

            stderr_data = self._consume_stderr(
                chan=chan, call_line_handler_func=call_line_handler_func
            )
            stderr_data = stderr_data.getvalue()

            stdout.write(stdout_data)
            stderr.write(stderr_data)

        while not exit_status_ready:
            current_time = time.time()
            elapsed_time = current_time - start_time

            if timeout and (elapsed_time > timeout):
                # TODO: Is this the right way to clean up?
                chan.close()

                stdout = sanitize_output(stdout.getvalue(), uses_pty=uses_pty)
                stderr = sanitize_output(stderr.getvalue(), uses_pty=uses_pty)
                raise SSHCommandTimeoutError(
                    cmd=cmd,
                    timeout=timeout,
                    ssh_connect_timeout=self.ssh_connect_timeout,
                    stdout=stdout,
                    stderr=stderr,
                )

            stdout_data = self._consume_stdout(
                chan=chan, call_line_handler_func=call_line_handler_func
            )
            stdout_data = stdout_data.getvalue()

            stderr_data = self._consume_stderr(
                chan=chan, call_line_handler_func=call_line_handler_func
            )
            stderr_data = stderr_data.getvalue()

            stdout.write(stdout_data)
            stderr.write(stderr_data)

            # We need to check the exit status here, because the command could
            # print some output and exit during this sleep below.
            exit_status_ready = chan.exit_status_ready()

            if exit_status_ready:
                break

            # Short sleep to prevent busy waiting
            concurrency.sleep(self.SLEEP_DELAY)
        # print('Wait over. Channel must be ready for host: %s' % self.hostname)

        # Receive the exit status code of the command we ran.
        status = chan.recv_exit_status()

        stdout = sanitize_output(stdout.getvalue(), uses_pty=uses_pty)
        stderr = sanitize_output(stderr.getvalue(), uses_pty=uses_pty)

        extra = {"_status": status, "_stdout": stdout, "_stderr": stderr}
        self.logger.debug("Command finished", extra=extra)

        return [stdout, stderr, status]

        Note: This function is based on paramiko's exec_command()
        method.

        :param timeout: How long to wait (in seconds) for the command to finish (optional).
        :type timeout: ``float``

        :param call_line_handler_func: True to call handle_stdout_line_func function for each line
                                       of received stdout and handle_stderr_line_func for each
                                       line of stderr.
        :type call_line_handler_func: ``bool``
        
st2common/st2common/runners/paramiko_ssh.py