1

这个问题是这个问题的后续:Using paramiko to send commands to an open shell that has an interactive element所以请在回答之前阅读。

我成功地能够将数据发送到阵列的系统外壳,但是我需要帮助弄清楚当阵列花费太长时间来运行我发送的脚本时如何实现超时。Paramikoexec_command有一个timeout=参数,但这在这里无济于事,因为我发送的唯一命令是"script"立即返回并等待通道上的输入,当我尝试实现时,它似乎破坏了函数的其余部分,因为没有任何返回数组。

然后该数组应该处理我发送的脚本并通过返回输出stdout,但是如果数组需要很长时间,我无法使连接超时,它会保留脚本的其余部分。

这是我的代码:

def run_script(self, script_name):
    """ Run a script on the remote array and return the stdout
    """
    try:
        common_functions_file = os.path.join(SCRIPT_DIR, 'zfs_common_functions.js')
        common_functions = open(common_functions_file).read().splitlines()
        # add common_functions to the top of the script
        script_contents = common_functions + open(script_name).read().splitlines()
        stdin, stdout, stderr = self._ssh.exec_command('script')
        for line in script_contents:
            # Skip lines with comments
            if re.match("^//", line):
                continue
            stdin.write(line)
            stdin.write('\n')
        stdin.write('.\n')
        stdin.flush()
        error = stderr.readlines()
        if len(error) == 0:
            try:
                output = ''.join(stdout.readlines())
                if(re.search('aksh', output)):
                    logger.warn("ZFS Shell Error: %s" % output)
                    return None
                return output
            except Exception as e:
                logger.exception(e)

        else:
            logger.error(error)
            return None
    except paramiko.SSHException as e:
        logger.warn(
            "Couldn't execute script on array %s: %s" % (array.name, e))

    except AttributeError as e:
        logger.exception(e)
        raise

    except Exception:
        raise
4

1 回答 1

3

我最终通过直接与通道交互来解决它,您可以设置超时:

def run_script(self, script_name):
    """ Run a script on the remote array and return the stdout
    """
    try:
        chan = self._ssh.get_transport().open_session()
        # five minute timeout on the channel communication
        chan.settimeout(5*60.0)
        common_functions_file = os.path.join(SCRIPT_DIR, 'zfs_common_functions.js')
        common_functions = open(common_functions_file).read().splitlines()
        # add common_functions to the top of the script
        script_contents = common_functions + open(script_name).read().splitlines()
        chan.exec_command('script')
        if chan.send_ready():
            chan.sendall("\n".join(script_contents))
            chan.send("\n.\n")

        results = StringIO()
        error = StringIO()
        bufsize = 1024
        while not chan.exit_status_ready():
            if chan.recv_ready():
                data = chan.recv(bufsize)
                while data:
                    results.write(data)
                    data = chan.recv(bufsize)

            if chan.recv_stderr_ready():
                error_buf = chan.recv_stderr(bufsize)
                while error_buf:
                    error.write(error_buf)
                    error_buf = chan.recv_stderr(bufsize)

        exit_status = chan.recv_exit_status()
        if exit_status == 0:
            return results.getvalue()
        else:
            raise ZfsScriptError(results.getvalue())

    except socket.timeout:
        logger.warn("%s: Timeout running %s" %(self.hostname, script_name))
        return None

    except paramiko.SSHException as e:
        logger.warn(
            "Couldn't execute script on array %s: %s" % (self.hostname, e))
        raise

    except AttributeError as e:
        logger.exception(e)
        raise

    except Exception:
        raise

    finally:
        results.close()
        error.close()
        chan.close()
于 2013-10-18T13:07:45.370 回答